Reorganise the tuskar files
The dashboards/infrastructure were moved to tuskar_ui, so were the Tuskar API helpers. Non-tuskar files were removed. The Infrastructure dashboard will become a Django Application available in the tuskar_ui package. Change-Id: I49c5d46cc16696c4c719ee2c6d65c42b03183ba9 Signed-off-by: Tomas Sedovic <tsedovic@redhat.com>
This commit is contained in:
		
							
								
								
									
										153
									
								
								doc/Makefile
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								doc/Makefile
									
									
									
									
									
								
							@@ -1,153 +0,0 @@
 | 
			
		||||
# Makefile for Sphinx documentation
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# You can set these variables from the command line.
 | 
			
		||||
SPHINXOPTS    =
 | 
			
		||||
SPHINXBUILD   = sphinx-build
 | 
			
		||||
PAPER         =
 | 
			
		||||
BUILDDIR      = build
 | 
			
		||||
 | 
			
		||||
# Internal variables.
 | 
			
		||||
PAPEROPT_a4     = -D latex_paper_size=a4
 | 
			
		||||
PAPEROPT_letter = -D latex_paper_size=letter
 | 
			
		||||
ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
 | 
			
		||||
# the i18n builder cannot share the environment and doctrees with the others
 | 
			
		||||
I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
 | 
			
		||||
 | 
			
		||||
.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 <target>' where <target> 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 "  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 "  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/Horizon.qhcp"
 | 
			
		||||
	@echo "To view the help file:"
 | 
			
		||||
	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Horizon.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/Horizon"
 | 
			
		||||
	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Horizon"
 | 
			
		||||
	@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."
 | 
			
		||||
 | 
			
		||||
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."
 | 
			
		||||
@@ -1,426 +0,0 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
#
 | 
			
		||||
# Horizon documentation build configuration file, created by
 | 
			
		||||
# sphinx-quickstart on Thu Oct 27 11:38:59 2011.
 | 
			
		||||
#
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
 | 
			
		||||
ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", ".."))
 | 
			
		||||
 | 
			
		||||
sys.path.insert(0, ROOT)
 | 
			
		||||
 | 
			
		||||
# This is required for ReadTheDocs.org, but isn't a bad idea anyway.
 | 
			
		||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'openstack_dashboard.settings'
 | 
			
		||||
 | 
			
		||||
import horizon.version
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def write_autodoc_index():
 | 
			
		||||
 | 
			
		||||
    def find_autodoc_modules(module_name, sourcedir):
 | 
			
		||||
        """returns a list of modules in the SOURCE directory"""
 | 
			
		||||
        modlist = []
 | 
			
		||||
        os.chdir(os.path.join(sourcedir, module_name))
 | 
			
		||||
        print "SEARCHING %s" % sourcedir
 | 
			
		||||
        for root, dirs, files in os.walk("."):
 | 
			
		||||
            for filename in files:
 | 
			
		||||
                if filename.endswith(".py"):
 | 
			
		||||
                    # remove the pieces of the root
 | 
			
		||||
                    elements = root.split(os.path.sep)
 | 
			
		||||
                    # replace the leading "." with the module name
 | 
			
		||||
                    elements[0] = module_name
 | 
			
		||||
                    # and get the base module name
 | 
			
		||||
                    base, extension = os.path.splitext(filename)
 | 
			
		||||
                    if not (base == "__init__"):
 | 
			
		||||
                        elements.append(base)
 | 
			
		||||
                    result = ".".join(elements)
 | 
			
		||||
                    #print result
 | 
			
		||||
                    modlist.append(result)
 | 
			
		||||
        return modlist
 | 
			
		||||
 | 
			
		||||
    RSTDIR = os.path.abspath(os.path.join(BASE_DIR, "sourcecode"))
 | 
			
		||||
    SRCS = {'horizon': ROOT,
 | 
			
		||||
            'openstack_dashboard': ROOT}
 | 
			
		||||
 | 
			
		||||
    EXCLUDED_MODULES = ('horizon.tests', 'openstack_dashboard.tests',)
 | 
			
		||||
    CURRENT_SOURCES = {}
 | 
			
		||||
 | 
			
		||||
    if not(os.path.exists(RSTDIR)):
 | 
			
		||||
        os.mkdir(RSTDIR)
 | 
			
		||||
    CURRENT_SOURCES[RSTDIR] = ['autoindex.rst']
 | 
			
		||||
 | 
			
		||||
    INDEXOUT = open(os.path.join(RSTDIR, "autoindex.rst"), "w")
 | 
			
		||||
    INDEXOUT.write("=================\n")
 | 
			
		||||
    INDEXOUT.write("Source Code Index\n")
 | 
			
		||||
    INDEXOUT.write("=================\n")
 | 
			
		||||
 | 
			
		||||
    for modulename, path in SRCS.items():
 | 
			
		||||
        sys.stdout.write("Generating source documentation for %s\n" %
 | 
			
		||||
                         modulename)
 | 
			
		||||
        INDEXOUT.write("\n%s\n" % modulename.capitalize())
 | 
			
		||||
        INDEXOUT.write("%s\n" % ("=" * len(modulename),))
 | 
			
		||||
        INDEXOUT.write(".. toctree::\n")
 | 
			
		||||
        INDEXOUT.write("   :maxdepth: 1\n")
 | 
			
		||||
        INDEXOUT.write("\n")
 | 
			
		||||
 | 
			
		||||
        MOD_DIR = os.path.join(RSTDIR, modulename)
 | 
			
		||||
        CURRENT_SOURCES[MOD_DIR] = []
 | 
			
		||||
        if not(os.path.exists(MOD_DIR)):
 | 
			
		||||
            os.mkdir(MOD_DIR)
 | 
			
		||||
        for module in find_autodoc_modules(modulename, path):
 | 
			
		||||
            if any([module.startswith(exclude) for exclude
 | 
			
		||||
                                                in EXCLUDED_MODULES]):
 | 
			
		||||
                print "Excluded module %s." % module
 | 
			
		||||
                continue
 | 
			
		||||
            mod_path = os.path.join(path, *module.split("."))
 | 
			
		||||
            generated_file = os.path.join(MOD_DIR, "%s.rst" % module)
 | 
			
		||||
 | 
			
		||||
            INDEXOUT.write("   %s/%s\n" % (modulename, module))
 | 
			
		||||
 | 
			
		||||
            # Find the __init__.py module if this is a directory
 | 
			
		||||
            if os.path.isdir(mod_path):
 | 
			
		||||
                source_file = ".".join((os.path.join(mod_path, "__init__"),
 | 
			
		||||
                                        "py",))
 | 
			
		||||
            else:
 | 
			
		||||
                source_file = ".".join((os.path.join(mod_path), "py"))
 | 
			
		||||
 | 
			
		||||
            CURRENT_SOURCES[MOD_DIR].append("%s.rst" % module)
 | 
			
		||||
            # Only generate a new file if the source has changed or we don't
 | 
			
		||||
            # have a doc file to begin with.
 | 
			
		||||
            if not os.access(generated_file, os.F_OK) or \
 | 
			
		||||
                    os.stat(generated_file).st_mtime < \
 | 
			
		||||
                    os.stat(source_file).st_mtime:
 | 
			
		||||
                print "Module %s updated, generating new documentation." \
 | 
			
		||||
                      % module
 | 
			
		||||
                FILEOUT = open(generated_file, "w")
 | 
			
		||||
                header = "The :mod:`%s` Module" % module
 | 
			
		||||
                FILEOUT.write("%s\n" % ("=" * len(header),))
 | 
			
		||||
                FILEOUT.write("%s\n" % header)
 | 
			
		||||
                FILEOUT.write("%s\n" % ("=" * len(header),))
 | 
			
		||||
                FILEOUT.write(".. automodule:: %s\n" % module)
 | 
			
		||||
                FILEOUT.write("  :members:\n")
 | 
			
		||||
                FILEOUT.write("  :undoc-members:\n")
 | 
			
		||||
                FILEOUT.write("  :show-inheritance:\n")
 | 
			
		||||
                FILEOUT.write("  :noindex:\n")
 | 
			
		||||
                FILEOUT.close()
 | 
			
		||||
 | 
			
		||||
    INDEXOUT.close()
 | 
			
		||||
 | 
			
		||||
    # Delete auto-generated .rst files for sources which no longer exist
 | 
			
		||||
    for directory, subdirs, files in list(os.walk(RSTDIR)):
 | 
			
		||||
        for old_file in files:
 | 
			
		||||
            if old_file not in CURRENT_SOURCES.get(directory, []):
 | 
			
		||||
                print "Removing outdated file for %s" % old_file
 | 
			
		||||
                os.remove(os.path.join(directory, old_file))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
write_autodoc_index()
 | 
			
		||||
 | 
			
		||||
# 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('.'))
 | 
			
		||||
 | 
			
		||||
# -- 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.autodoc',
 | 
			
		||||
              'sphinx.ext.intersphinx',
 | 
			
		||||
              'sphinx.ext.todo',
 | 
			
		||||
              'sphinx.ext.coverage',
 | 
			
		||||
              'sphinx.ext.pngmath',
 | 
			
		||||
              'sphinx.ext.viewcode',
 | 
			
		||||
              'oslo.sphinx',
 | 
			
		||||
              ]
 | 
			
		||||
 | 
			
		||||
# 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'
 | 
			
		||||
 | 
			
		||||
# General information about the project.
 | 
			
		||||
project = u'Horizon'
 | 
			
		||||
copyright = u'2012, OpenStack, LLC'
 | 
			
		||||
 | 
			
		||||
# 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.
 | 
			
		||||
#
 | 
			
		||||
# The short X.Y version.
 | 
			
		||||
version = horizon.version.version_info.version_string()
 | 
			
		||||
# The full version, including alpha/beta/rc tags.
 | 
			
		||||
release = horizon.version.version_info.release_string()
 | 
			
		||||
 | 
			
		||||
# The language for content autogenerated by Sphinx. Refer to documentation
 | 
			
		||||
# for a list of supported languages.
 | 
			
		||||
#language = None
 | 
			
		||||
 | 
			
		||||
# 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 = ['**/#*', '**~', '**/#*#']
 | 
			
		||||
 | 
			
		||||
# 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 = []
 | 
			
		||||
 | 
			
		||||
primary_domain = 'py'
 | 
			
		||||
nitpicky = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- 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_path = ['.']
 | 
			
		||||
# html_theme = '_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 = {
 | 
			
		||||
    "nosidebar": "false"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
 | 
			
		||||
# 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 = None
 | 
			
		||||
 | 
			
		||||
# 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']
 | 
			
		||||
 | 
			
		||||
# 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'
 | 
			
		||||
git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1"
 | 
			
		||||
html_last_updated_fmt = os.popen(git_cmd).read()
 | 
			
		||||
 | 
			
		||||
# 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 = 'Horizondoc'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for LaTeX output -------------------------------------------------
 | 
			
		||||
 | 
			
		||||
latex_elements = {
 | 
			
		||||
# 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]).
 | 
			
		||||
latex_documents = [
 | 
			
		||||
    ('index', 'Horizon.tex', u'Horizon Documentation',
 | 
			
		||||
     u'OpenStack, LLC', '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 = False
 | 
			
		||||
 | 
			
		||||
# If true, show URL addresses after external links.
 | 
			
		||||
#latex_show_urls = False
 | 
			
		||||
 | 
			
		||||
# Documents to append as an appendix to all manuals.
 | 
			
		||||
#latex_appendices = []
 | 
			
		||||
 | 
			
		||||
# If false, no module index is generated.
 | 
			
		||||
#latex_domain_indices = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for manual page output -------------------------------------------
 | 
			
		||||
 | 
			
		||||
# One entry per manual page. List of tuples
 | 
			
		||||
# (source start file, name, description, authors, manual section).
 | 
			
		||||
man_pages = [
 | 
			
		||||
    ('index', 'horizon', u'Horizon Documentation',
 | 
			
		||||
     [u'OpenStack'], 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', 'Horizon', u'Horizon Documentation', u'OpenStack',
 | 
			
		||||
     'Horizon', 'One line description of 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'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# -- Options for Epub output --------------------------------------------------
 | 
			
		||||
 | 
			
		||||
# Bibliographic Dublin Core info.
 | 
			
		||||
epub_title = u'Horizon'
 | 
			
		||||
epub_author = u'OpenStack'
 | 
			
		||||
epub_publisher = u'OpenStack'
 | 
			
		||||
epub_copyright = u'2012, OpenStack'
 | 
			
		||||
 | 
			
		||||
# The language of the text. It defaults to the language option
 | 
			
		||||
# or en if the language is not set.
 | 
			
		||||
#epub_language = ''
 | 
			
		||||
 | 
			
		||||
# The scheme of the identifier. Typical schemes are ISBN or URL.
 | 
			
		||||
#epub_scheme = ''
 | 
			
		||||
 | 
			
		||||
# The unique identifier of the text. This can be an ISBN number
 | 
			
		||||
# or the project homepage.
 | 
			
		||||
#epub_identifier = ''
 | 
			
		||||
 | 
			
		||||
# A unique identification for the text.
 | 
			
		||||
#epub_uid = ''
 | 
			
		||||
 | 
			
		||||
# A tuple containing the cover image and cover page html template filenames.
 | 
			
		||||
#epub_cover = ()
 | 
			
		||||
 | 
			
		||||
# HTML files that should be inserted before the pages created by sphinx.
 | 
			
		||||
# The format is a list of tuples containing the path and title.
 | 
			
		||||
#epub_pre_files = []
 | 
			
		||||
 | 
			
		||||
# HTML files shat should be inserted after the pages created by sphinx.
 | 
			
		||||
# The format is a list of tuples containing the path and title.
 | 
			
		||||
#epub_post_files = []
 | 
			
		||||
 | 
			
		||||
# A list of files that should not be packed into the epub file.
 | 
			
		||||
#epub_exclude_files = []
 | 
			
		||||
 | 
			
		||||
# The depth of the table of contents in toc.ncx.
 | 
			
		||||
#epub_tocdepth = 3
 | 
			
		||||
 | 
			
		||||
# Allow duplicate toc entries.
 | 
			
		||||
#epub_tocdup = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Example configuration for intersphinx: refer to the Python standard library.
 | 
			
		||||
intersphinx_mapping = {'python': ('http://docs.python.org/', None),
 | 
			
		||||
                       'django':
 | 
			
		||||
                           ('http://docs.djangoproject.com/en/dev/_objects/'),
 | 
			
		||||
                       'nova': ('http://nova.openstack.org', None),
 | 
			
		||||
                       'swift': ('http://swift.openstack.org', None),
 | 
			
		||||
                       'keystone': ('http://keystone.openstack.org', None),
 | 
			
		||||
                       'glance': ('http://glance.openstack.org', None)}
 | 
			
		||||
@@ -1,203 +0,0 @@
 | 
			
		||||
==================
 | 
			
		||||
Contributing Guide
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
First and foremost, thank you for wanting to contribute! It's the only way
 | 
			
		||||
open source works!
 | 
			
		||||
 | 
			
		||||
Before you dive into writing patches, here are some of the basics:
 | 
			
		||||
 | 
			
		||||
* Project page: http://launchpad.net/horizon
 | 
			
		||||
* Bug tracker: https://bugs.launchpad.net/horizon
 | 
			
		||||
* Source code: https://github.com/openstack/horizon
 | 
			
		||||
* Code review: https://review.openstack.org/#q,status:open+project:openstack/horizon,n,z
 | 
			
		||||
* Jenkins build status: https://jenkins.openstack.org/view/Horizon/
 | 
			
		||||
* IRC Channel: #openstack-horizon on Freenode.
 | 
			
		||||
 | 
			
		||||
Making Contributions
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
Getting Started
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
We'll start by assuming you've got a working checkout of the repository (if
 | 
			
		||||
not then please see the :doc:`quickstart`).
 | 
			
		||||
 | 
			
		||||
Second, you'll need to take care of a couple administrative tasks:
 | 
			
		||||
 | 
			
		||||
#. Create an account on Launchpad.
 | 
			
		||||
#. Sign the `OpenStack Contributor License Agreement`_ and follow the associated
 | 
			
		||||
   instructions to verify your signature.
 | 
			
		||||
#. Join the `Horizon Developers`_ team on Launchpad.
 | 
			
		||||
#. Follow the `instructions for setting up git-review`_ in your
 | 
			
		||||
   development environment.
 | 
			
		||||
 | 
			
		||||
Whew! Got that all that? Okay! You're good to go.
 | 
			
		||||
 | 
			
		||||
Ways To Contribute
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
The easiest way to get started with Horizon's code is to pick a bug on
 | 
			
		||||
Launchpad that interests you, and start working on that. Alternatively, if
 | 
			
		||||
there's an OpenStack API feature you would like to see implemented in Horizon
 | 
			
		||||
feel free to try building it.
 | 
			
		||||
 | 
			
		||||
If those are too big, there are lots of great ways to get involved without
 | 
			
		||||
plunging in head-first:
 | 
			
		||||
 | 
			
		||||
* Report bugs, triage new tickets, and review old tickets on
 | 
			
		||||
  the `bug tracker`_.
 | 
			
		||||
* Propose ideas for improvements via Launchpad Blueprints, via the
 | 
			
		||||
  mailing list on the project page, or on IRC.
 | 
			
		||||
* Write documentation!
 | 
			
		||||
* Write unit tests for untested code!
 | 
			
		||||
 | 
			
		||||
.. _`bug tracker`: https://bugs.launchpad.net/horizon
 | 
			
		||||
 | 
			
		||||
Choosing Issues To Work On
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
In general, if you want to write code, there are three cases for issues
 | 
			
		||||
you might want to work on:
 | 
			
		||||
 | 
			
		||||
#. Confirmed bugs
 | 
			
		||||
#. Approved blueprints (features)
 | 
			
		||||
#. New bugs you've discovered
 | 
			
		||||
 | 
			
		||||
If you have an idea for a new feature that isn't in a blueprint yet, it's
 | 
			
		||||
a good idea to write the blueprint first so you don't end up writing a bunch
 | 
			
		||||
of code that may not go in the direction the community wants.
 | 
			
		||||
 | 
			
		||||
For bugs, open the bug first, but if you can reproduce the bug reliably and
 | 
			
		||||
identify its cause then it's usually safe to start working on it. However,
 | 
			
		||||
getting independent confirmation (and verifying that it's not a duplicate)
 | 
			
		||||
is always a good idea if you can be patient.
 | 
			
		||||
 | 
			
		||||
After You Write Your Patch
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
Once you've made your changes, there are a few things to do:
 | 
			
		||||
 | 
			
		||||
* Make sure the unit tests pass: ``./run_tests.sh``
 | 
			
		||||
* Make sure PEP8 is clean: ``./run_tests.sh --pep8``
 | 
			
		||||
* Make sure your code is up-to-date with the latest master: ``git pull --rebase``
 | 
			
		||||
* Finally, run ``git review`` to upload your changes to Gerrit for review.
 | 
			
		||||
 | 
			
		||||
The Horizon core developers will be notified of the new review and will examine
 | 
			
		||||
it in a timely fashion, either offering feedback or approving it to be merged.
 | 
			
		||||
If the review is approved, it is sent to Jenkins to verify the unit tests pass
 | 
			
		||||
and it can be merged cleanly. Once Jenkins approves it, the change will be
 | 
			
		||||
merged to the master repository and it's time to celebrate!
 | 
			
		||||
 | 
			
		||||
.. _`OpenStack Contributor License Agreement`: http://wiki.openstack.org/CLA
 | 
			
		||||
.. _`OpenStack Contributors`: https://launchpad.net/~openstack-cla
 | 
			
		||||
.. _`Horizon Developers`: https://launchpad.net/~horizon
 | 
			
		||||
.. _`instructions for setting up git-review`: http://wiki.openstack.org/GerritWorkflow
 | 
			
		||||
 | 
			
		||||
Etiquette
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
The community's guidelines for etiquette are fairly simple:
 | 
			
		||||
 | 
			
		||||
* Treat everyone respectfully and professionally.
 | 
			
		||||
* If a bug is "in progress" in the bug tracker, don't start working on it
 | 
			
		||||
  without contacting the author. Try on IRC, or via the launchpad email
 | 
			
		||||
  contact link. If you don't get a response after a reasonable time, then go
 | 
			
		||||
  ahead. Checking first avoids duplicate work and makes sure nobody's toes
 | 
			
		||||
  get stepped on.
 | 
			
		||||
* If a blueprint is assigned, even if it hasn't been started, be sure you
 | 
			
		||||
  contact the assignee before taking it on. These larger issues often have a
 | 
			
		||||
  history of discussion or specific implementation details that the assignee
 | 
			
		||||
  may be aware of that you are not.
 | 
			
		||||
* Please don't re-open tickets closed by a core developer. If you disagree with
 | 
			
		||||
  the decision on the ticket, the appropriate solution is to take it up on
 | 
			
		||||
  IRC or the mailing list.
 | 
			
		||||
* Give credit where credit is due; if someone helps you substantially with
 | 
			
		||||
  a piece of code, it's polite (though not required) to thank them in your
 | 
			
		||||
  commit message.
 | 
			
		||||
 | 
			
		||||
Code Style
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
Python
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
We follow PEP8_ for all our Python code, and use ``pep8.py`` (available
 | 
			
		||||
via the shortcut ``./run_tests.sh --pep8``) to validate that our code
 | 
			
		||||
meets proper Python style guidelines.
 | 
			
		||||
 | 
			
		||||
.. _PEP8: http://www.python.org/dev/peps/pep-0008/
 | 
			
		||||
 | 
			
		||||
Django
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
Additionally, we follow `Django's style guide`_ for templates, views, and
 | 
			
		||||
other miscellany.
 | 
			
		||||
 | 
			
		||||
.. _Django's style guide: https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/
 | 
			
		||||
 | 
			
		||||
JavaScript
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
As a project, Horizon adheres to code quality standards for our JavaScript
 | 
			
		||||
just as we do for our Python. To that end we recommend (but do not strictly
 | 
			
		||||
enforce) the use of JSLint_ to validate some general best practices.
 | 
			
		||||
 | 
			
		||||
The default options are mostly good, but the following accommodate some
 | 
			
		||||
allowances we make:
 | 
			
		||||
 | 
			
		||||
* Set ``Indentation`` to ``2``.
 | 
			
		||||
* Enable the ``Assume console, alert, ...`` option.
 | 
			
		||||
* Enable the ``Assume a browser`` option.
 | 
			
		||||
* Enable the ``Tolerate missing 'use strict' pragma`` option.
 | 
			
		||||
* Clear the ``Maximum number of errors`` field.
 | 
			
		||||
* Add ``horizon,$`` to the ``Predefined`` list.
 | 
			
		||||
 | 
			
		||||
.. _JSLint: http://jslint.com/
 | 
			
		||||
 | 
			
		||||
CSS
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
Style guidelines for CSS are currently quite minimal. Do your best to make the
 | 
			
		||||
code readable and well-organized. Two spaces are preferred for indentation
 | 
			
		||||
so as to match both the JavaScript and HTML files.
 | 
			
		||||
 | 
			
		||||
HTML
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Again, readability is paramount; however be conscientous of how the browser
 | 
			
		||||
will handle whitespace when rendering the output. Two spaces is the preferred
 | 
			
		||||
indentation style to match all front-end code.
 | 
			
		||||
 | 
			
		||||
Documentation
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Horizon's documentation is written in reStructuredText and uses Sphinx for
 | 
			
		||||
additional parsing and functionality, and should follow
 | 
			
		||||
standard practices for writing reST. This includes:
 | 
			
		||||
 | 
			
		||||
* Flow paragraphs such that lines wrap at 80 characters or less.
 | 
			
		||||
* Use proper grammar, spelling, capitalization and punctuation at all times.
 | 
			
		||||
* Make use of Sphinx's autodoc feature to document modules, classes
 | 
			
		||||
  and functions. This keeps the docs close to the source.
 | 
			
		||||
* Where possible, use Sphinx's cross-reference syntax (e.g.
 | 
			
		||||
  ``:class:`~horizon.foo.Bar```) when referring to other Horizon components.
 | 
			
		||||
  The better-linked our docs are, the easier they are to use.
 | 
			
		||||
 | 
			
		||||
Be sure to generate the documentation before submitting a patch for review.
 | 
			
		||||
Unexpected warnings often appear when building the documentation, and slight
 | 
			
		||||
reST syntax errors frequently cause links or cross-references not to work
 | 
			
		||||
correctly.
 | 
			
		||||
 | 
			
		||||
Conventions
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
Simply by convention, we have a few rules about naming:
 | 
			
		||||
 | 
			
		||||
  * The term "project" is used in place of Keystone's "tenant" terminology
 | 
			
		||||
    in all user-facing text. The term "tenant" is still used in API code to
 | 
			
		||||
    make things more obvious for developers.
 | 
			
		||||
 | 
			
		||||
  * The term "dashboard" refers to a top-level dashboard class, and "panel" to
 | 
			
		||||
    the sub-items within a dashboard. Referring to a panel as a dashboard is
 | 
			
		||||
    both confusing and incorrect.
 | 
			
		||||
@@ -1,37 +0,0 @@
 | 
			
		||||
==========================
 | 
			
		||||
Frequently Asked Questions
 | 
			
		||||
==========================
 | 
			
		||||
 | 
			
		||||
What is the relationship between ``Dashboards``, ``Panels``, and navigation?
 | 
			
		||||
 | 
			
		||||
    The navigational structure is strongly encouraged to flow from
 | 
			
		||||
    ``Dashboard`` objects as top-level navigation items to ``Panel`` objects as
 | 
			
		||||
    sub-navigation items as in the current implementation. Template tags
 | 
			
		||||
    are provided to automatically generate this structure.
 | 
			
		||||
 | 
			
		||||
    That said, you are not required to use the provided tools and can write
 | 
			
		||||
    templates and URLconfs by hand to create any desired structure.
 | 
			
		||||
 | 
			
		||||
Does a panel have to be an app in ``INSTALLED_APPS``?
 | 
			
		||||
 | 
			
		||||
    A panel can live in any Python module. It can be a standalone which ties
 | 
			
		||||
    into an existing dashboard, or it can be contained alongside others within
 | 
			
		||||
    a larger dashboard "app". There is no strict enforcement here. Python
 | 
			
		||||
    is "a language for consenting adults." A module containing a Panel does
 | 
			
		||||
    not need to be added to ``INSTALLED_APPS``, but this is a common and
 | 
			
		||||
    convenient way to load a standalone panel.
 | 
			
		||||
 | 
			
		||||
Could I hook an external service into a panel using, for example, an iFrame?
 | 
			
		||||
 | 
			
		||||
    Panels are just entry-points to hook views into the larger dashboard
 | 
			
		||||
    navigational structure and enforce common attributes like RBAC. The
 | 
			
		||||
    view and corresponding templates can contain anything you would like,
 | 
			
		||||
    including iFrames.
 | 
			
		||||
 | 
			
		||||
What does this mean for visual design?
 | 
			
		||||
 | 
			
		||||
    The ability to add an arbitrary number of top-level navigational items
 | 
			
		||||
    (``Dashboard`` objects) poses a new design challenge. Horizon's lead
 | 
			
		||||
    designer has taken on the challenge of providing a reference design
 | 
			
		||||
    for Horizon which supports this possibility.
 | 
			
		||||
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
========
 | 
			
		||||
Glossary
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
Horizon
 | 
			
		||||
 | 
			
		||||
    The OpenStack dashboard project. Also the name of the top-level
 | 
			
		||||
    Python object which handles registration for the app.
 | 
			
		||||
 | 
			
		||||
Dashboard
 | 
			
		||||
 | 
			
		||||
    A Python class representing a top-level navigation item (e.g. "project")
 | 
			
		||||
    which provides a consistent API for Horizon-compatible applications.
 | 
			
		||||
 | 
			
		||||
Panel
 | 
			
		||||
 | 
			
		||||
    A Python class representing a sub-navigation item (e.g. "instances")
 | 
			
		||||
    which contains all the necessary logic (views, forms, tests, etc.) for
 | 
			
		||||
    that interface.
 | 
			
		||||
 | 
			
		||||
Project
 | 
			
		||||
 | 
			
		||||
    Used in user-facing text in place of the term "Tenant" which is Keystone's
 | 
			
		||||
    word.
 | 
			
		||||
@@ -1,127 +0,0 @@
 | 
			
		||||
..
 | 
			
		||||
      Copyright 2012 OpenStack, LLC
 | 
			
		||||
      All Rights Reserved.
 | 
			
		||||
 | 
			
		||||
      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.
 | 
			
		||||
 | 
			
		||||
========================================
 | 
			
		||||
Horizon: The OpenStack Dashboard Project
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
Introduction
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
Horizon is the canonical implementation of `Openstack's Dashboard
 | 
			
		||||
<https://github.com/openstack/horizon>`_, which provides a web based user
 | 
			
		||||
interface to OpenStack services including Nova, Swift, Keystone, etc.
 | 
			
		||||
 | 
			
		||||
For a more in-depth look at Horizon and its architecture, see the
 | 
			
		||||
:doc:`Introduction to Horizon <intro>`.
 | 
			
		||||
 | 
			
		||||
To learn what you need to know to get going, see the :doc:`quickstart`.
 | 
			
		||||
 | 
			
		||||
Getting Started With Horizon
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
How to use Horizon in your own projects.
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   intro
 | 
			
		||||
   quickstart
 | 
			
		||||
   topics/tutorial
 | 
			
		||||
   topics/deployment
 | 
			
		||||
   topics/settings
 | 
			
		||||
   topics/customizing
 | 
			
		||||
 | 
			
		||||
Developer Docs
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
For those wishing to develop Horizon itself, or go in-depth with building
 | 
			
		||||
your own :class:`~horizon.Dashboard` or :class:`~horizon.Panel` classes,
 | 
			
		||||
the following documentation is provided.
 | 
			
		||||
 | 
			
		||||
General information
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
Brief guides to areas of interest and importance when developing Horizon.
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   contributing
 | 
			
		||||
   testing
 | 
			
		||||
 | 
			
		||||
Topic Guides
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Information on how to work with specific areas of Horizon can be found in
 | 
			
		||||
the following topic guides.
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   topics/tables
 | 
			
		||||
   topics/testing
 | 
			
		||||
 | 
			
		||||
API Reference
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
In-depth documentation for Horizon and its APIs.
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   ref/run_tests
 | 
			
		||||
   ref/horizon
 | 
			
		||||
   ref/workflows
 | 
			
		||||
   ref/tables
 | 
			
		||||
   ref/tabs
 | 
			
		||||
   ref/forms
 | 
			
		||||
   ref/middleware
 | 
			
		||||
   ref/context_processors
 | 
			
		||||
   ref/decorators
 | 
			
		||||
   ref/exceptions
 | 
			
		||||
   ref/test
 | 
			
		||||
 | 
			
		||||
Source Code Reference
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
Auto-generated reference for the complete source code.
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   sourcecode/autoindex
 | 
			
		||||
 | 
			
		||||
Release Notes
 | 
			
		||||
=============
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :glob:
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   releases/*
 | 
			
		||||
 | 
			
		||||
Information
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
.. toctree::
 | 
			
		||||
   :maxdepth: 1
 | 
			
		||||
 | 
			
		||||
   faq
 | 
			
		||||
   glossary
 | 
			
		||||
 | 
			
		||||
* :ref:`genindex`
 | 
			
		||||
* :ref:`modindex`
 | 
			
		||||
@@ -1,124 +0,0 @@
 | 
			
		||||
===================
 | 
			
		||||
Introducing Horizon
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
.. contents:: Contents:
 | 
			
		||||
   :local:
 | 
			
		||||
 | 
			
		||||
Values
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
    "Think simple" as my old master used to say - meaning reduce
 | 
			
		||||
    the whole of its parts into the simplest terms, getting back
 | 
			
		||||
    to first principles.
 | 
			
		||||
 | 
			
		||||
    -- Frank Lloyd Wright
 | 
			
		||||
 | 
			
		||||
Horizon holds several key values at the core of its design and architecture:
 | 
			
		||||
 | 
			
		||||
    * Core Support: Out-of-the-box support for all core OpenStack projects.
 | 
			
		||||
    * Extensible: Anyone can add a new component as a "first-class citizen".
 | 
			
		||||
    * Manageable: The core codebase should be simple and easy-to-navigate.
 | 
			
		||||
    * Consistent: Visual and interaction paradigms are maintained throughout.
 | 
			
		||||
    * Stable: A reliable API with an emphasis on backwards-compatibility.
 | 
			
		||||
    * Usable: Providing an *awesome* interface that people *want* to use.
 | 
			
		||||
 | 
			
		||||
The only way to attain and uphold those ideals is to make it *easy* for
 | 
			
		||||
developers to implement those values.
 | 
			
		||||
 | 
			
		||||
History
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
Horizon started life as a single app to manage OpenStack's compute project.
 | 
			
		||||
As such, all it needed was a set of views, templates, and API calls.
 | 
			
		||||
 | 
			
		||||
From there it grew to support multiple OpenStack projects and APIs gradually,
 | 
			
		||||
arranged rigidly into "dash" and "syspanel" groupings.
 | 
			
		||||
 | 
			
		||||
During the "Diablo" release cycle an initial plugin system was added using
 | 
			
		||||
signals to hook in additional URL patterns and add links into the "dash"
 | 
			
		||||
and "syspanel" navigation.
 | 
			
		||||
 | 
			
		||||
This incremental growth served the goal of "Core Support" phenomenally, but
 | 
			
		||||
left "Extensible" and "Manageable" behind. And while the other key values took
 | 
			
		||||
shape of their own accord, it was time to re-architect for an extensible,
 | 
			
		||||
modular future.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The Current Architecture & How It Meets Our Values
 | 
			
		||||
==================================================
 | 
			
		||||
 | 
			
		||||
At its core, **Horizon should be a registration pattern for
 | 
			
		||||
applications to hook into**. Here's what that means and how it is
 | 
			
		||||
implemented in terms of our values:
 | 
			
		||||
 | 
			
		||||
Core Support
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Horizon ships with three central dashboards, a "User Dashboard", a
 | 
			
		||||
"System Dashboard", and a "Settings" dashboard. Between these three they
 | 
			
		||||
cover the core OpenStack applications and deliver on Core Support.
 | 
			
		||||
 | 
			
		||||
The Horizon application also ships with a set of API abstractions
 | 
			
		||||
for the core OpenStack projects in order to provide a consistent, stable set
 | 
			
		||||
of reusable methods for developers. Using these abstractions, developers
 | 
			
		||||
working on Horizon don't need to be intimately familiar with the APIs of
 | 
			
		||||
each OpenStack project.
 | 
			
		||||
 | 
			
		||||
Extensible
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
A Horizon dashboard application is based around the :class:`~horizon.Dashboard`
 | 
			
		||||
class that provides a consistent API and set of capabilities for both
 | 
			
		||||
core OpenStack dashboard apps shipped with Horizon and equally for third-party
 | 
			
		||||
apps. The :class:`~horizon.Dashboard` class is treated as a top-level
 | 
			
		||||
navigation item.
 | 
			
		||||
 | 
			
		||||
Should a developer wish to provide functionality within an existing dashboard
 | 
			
		||||
(e.g. adding a monitoring panel to the user dashboard) the simple registration
 | 
			
		||||
pattern makes it possible to write an app which hooks into other dashboards
 | 
			
		||||
just as easily as creating a new dashboard. All you have to do is import the
 | 
			
		||||
dashboard you wish to modify.
 | 
			
		||||
 | 
			
		||||
Manageable
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
Within the application, there is a simple method for registering a
 | 
			
		||||
:class:`~horizon.Panel` (sub-navigation items). Each panel contains the
 | 
			
		||||
necessary logic (views, forms, tests, etc.) for that interface. This granular
 | 
			
		||||
breakdown prevents files (such as ``api.py``) from becoming thousands of
 | 
			
		||||
lines long and makes code easy to find by correlating it directly to the
 | 
			
		||||
navigation.
 | 
			
		||||
 | 
			
		||||
Consistent
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
By providing the necessary core classes to build from, as well as a
 | 
			
		||||
solid set of reusable templates and additional tools (base form classes,
 | 
			
		||||
base widget classes, template tags, and perhaps even class-based views)
 | 
			
		||||
we can maintain consistency across applications.
 | 
			
		||||
 | 
			
		||||
Stable
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
By architecting around these core classes and reusable components we
 | 
			
		||||
create an implicit contract that changes to these components will be
 | 
			
		||||
made in the most backwards-compatible ways whenever possible.
 | 
			
		||||
 | 
			
		||||
Usable
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
Ultimately that's up to each and every developer that touches the code,
 | 
			
		||||
but if we get all the other goals out of the way then we are free to focus
 | 
			
		||||
on the best possible experience.
 | 
			
		||||
 | 
			
		||||
.. seealso::
 | 
			
		||||
 | 
			
		||||
    :doc:`Quickstart <quickstart>`
 | 
			
		||||
        A short guide to getting started with using Horizon.
 | 
			
		||||
 | 
			
		||||
    :doc:`Frequently Asked Questions <faq>`
 | 
			
		||||
        Common questions and answers.
 | 
			
		||||
 | 
			
		||||
    :doc:`Glossary <glossary>`
 | 
			
		||||
        Common terms and their definitions.
 | 
			
		||||
@@ -1,214 +0,0 @@
 | 
			
		||||
==================
 | 
			
		||||
Horizon Quickstart
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
Setup
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
To setup an Horizon development environment simply clone the Horizon git
 | 
			
		||||
repository from http://github.com/openstack/horizon and execute the
 | 
			
		||||
``run_tests.sh`` script from the root folder (see :doc:`ref/run_tests`)::
 | 
			
		||||
 | 
			
		||||
    > git clone https://github.com/openstack/horizon.git
 | 
			
		||||
    > cd horizon
 | 
			
		||||
    > ./run_tests.sh
 | 
			
		||||
 | 
			
		||||
Next you will need to setup your Django application config by copying ``openstack_dashboard/local/local_settings.py.example`` to ``openstack_dashboard/local_settings.py``. To do this quickly you can use the following command::
 | 
			
		||||
 | 
			
		||||
    > cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py
 | 
			
		||||
 | 
			
		||||
Horizon assumes a single end-point for OpenStack services which defaults to
 | 
			
		||||
the local host (127.0.0.1). If this is not the case change the
 | 
			
		||||
``OPENSTACK_HOST`` setting in the ``openstack_dashboard/local/local_settings.py`` file, to the actual IP address of the OpenStack end-point Horizon should use.
 | 
			
		||||
 | 
			
		||||
To start the Horizon development server use the Django ``manage.py`` utility
 | 
			
		||||
with the context of the virtual environment::
 | 
			
		||||
 | 
			
		||||
    > tools/with_venv.sh ./manage.py runserver
 | 
			
		||||
 | 
			
		||||
Alternately specify the listen IP and port::
 | 
			
		||||
 | 
			
		||||
    > tools/with_venv.sh ./manage.py runserver 0.0.0.0:8080
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    If you would like to run commands without the prefix of ``tools/with_venv.sh`` you may source your environment directly. This will remain active as long as your shell session stays open::
 | 
			
		||||
 | 
			
		||||
    > source .venv/bin/activate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Once the Horizon server is running point a web browser to http://localhost:8000
 | 
			
		||||
or to the IP and port the server is listening for.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    The ``DevStack`` project (http://devstack.org/) can be used to install
 | 
			
		||||
    an OpenStack development environment from scratch.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    The minimum required set of OpenStack services running includes the
 | 
			
		||||
    following:
 | 
			
		||||
 | 
			
		||||
    * Nova (compute, api, scheduler, and network)
 | 
			
		||||
    * Glance
 | 
			
		||||
    * Keystone
 | 
			
		||||
 | 
			
		||||
    Optional support is provided for Swift.
 | 
			
		||||
 | 
			
		||||
Horizon's Structure
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
This project is a bit different from other OpenStack projects in that it has
 | 
			
		||||
two very distinct components underneath it: ``horizon``, and
 | 
			
		||||
``openstack_dashboard``.
 | 
			
		||||
 | 
			
		||||
The ``horizon`` directory holds the generic libraries and components that can
 | 
			
		||||
be used in any Django project.
 | 
			
		||||
 | 
			
		||||
The ``openstack_dashboard`` directory contains a reference Django project that
 | 
			
		||||
uses ``horizon``.
 | 
			
		||||
 | 
			
		||||
For development, both pieces share an environment which (by default) is
 | 
			
		||||
built with the ``tools/install_venv.py`` script. That script creates a
 | 
			
		||||
virtualenv and installs all the necessary packages.
 | 
			
		||||
 | 
			
		||||
If dependencies are added to either ``horizon`` or ``openstack_dashboard``,
 | 
			
		||||
they should be added to ``requirements.txt``.
 | 
			
		||||
 | 
			
		||||
  .. important::
 | 
			
		||||
 | 
			
		||||
    If you do anything which changes the environment (adding new dependencies
 | 
			
		||||
    or renaming directories are both great examples) be sure to increment the
 | 
			
		||||
    ``environment_version`` counter in :doc:`run_tests.sh <ref/run_tests>`.
 | 
			
		||||
 | 
			
		||||
Project
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
INSTALLED_APPS
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
At the project level you add Horizon and any desired dashboards to your
 | 
			
		||||
``settings.INSTALLED_APPS``::
 | 
			
		||||
 | 
			
		||||
    INSTALLED_APPS = (
 | 
			
		||||
        'openstack_dashboard',
 | 
			
		||||
        ...
 | 
			
		||||
        'horizon',
 | 
			
		||||
        'openstack_dashboard.dashboards.project',
 | 
			
		||||
        'openstack_dashboard.dashboards.admin',
 | 
			
		||||
        'openstack_dashboard.dashboards.settings',
 | 
			
		||||
        ...
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
URLs
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
Then you add a single line to your project's ``urls.py``::
 | 
			
		||||
 | 
			
		||||
    url(r'', include(horizon.urls)),
 | 
			
		||||
 | 
			
		||||
Those urls are automatically constructed based on the registered Horizon apps.
 | 
			
		||||
If a different URL structure is desired it can be constructed by hand.
 | 
			
		||||
 | 
			
		||||
Templates
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
Pre-built template tags generate navigation. In your ``nav.html``
 | 
			
		||||
template you might have the following::
 | 
			
		||||
 | 
			
		||||
    {% load horizon %}
 | 
			
		||||
 | 
			
		||||
    <div class='nav'>
 | 
			
		||||
        {% horizon_main_nav %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
And in your ``sidebar.html`` you might have::
 | 
			
		||||
 | 
			
		||||
    {% load horizon %}
 | 
			
		||||
 | 
			
		||||
    <div class='sidebar'>
 | 
			
		||||
        {% horizon_dashboard_nav %}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
These template tags are aware of the current "active" dashboard and panel
 | 
			
		||||
via template context variables and will render accordingly.
 | 
			
		||||
 | 
			
		||||
Application
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
Structure
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
An application would have the following structure (we'll use syspanel as
 | 
			
		||||
an example)::
 | 
			
		||||
 | 
			
		||||
    project/
 | 
			
		||||
    |---__init__.py
 | 
			
		||||
    |---dashboard.py <-----Registers the app with Horizon and sets dashboard properties
 | 
			
		||||
    |---overview/
 | 
			
		||||
    |---images_and_snapshots/
 | 
			
		||||
        |-- images
 | 
			
		||||
        |-- __init__.py
 | 
			
		||||
        |---panel.py <-----Registers the panel in the app and defines panel properties
 | 
			
		||||
        |-- snapshots/
 | 
			
		||||
        |-- templates/
 | 
			
		||||
        |-- tests.py
 | 
			
		||||
        |-- urls.py
 | 
			
		||||
        |-- views.py
 | 
			
		||||
        ...
 | 
			
		||||
    ...
 | 
			
		||||
 | 
			
		||||
Dashboard Classes
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
Inside of ``dashboard.py`` you would have a class definition and the registration
 | 
			
		||||
process::
 | 
			
		||||
 | 
			
		||||
    import horizon
 | 
			
		||||
 | 
			
		||||
    ....
 | 
			
		||||
    # ObjectStorePanels is an example for a PanelGroup
 | 
			
		||||
    # for panel classes in general, see below
 | 
			
		||||
    class ObjectStorePanels(horizon.PanelGroup):
 | 
			
		||||
        slug = "object_store"
 | 
			
		||||
        name = _("Object Store")
 | 
			
		||||
        panels = ('containers',)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Project(horizon.Dashboard):
 | 
			
		||||
        name = _("Project") # Appears in navigation
 | 
			
		||||
        slug = "project"    # Appears in URL
 | 
			
		||||
        # panels may be strings or refer to classes, such as
 | 
			
		||||
        # ObjectStorePanels
 | 
			
		||||
        panels = (BasePanels, NetworkPanels, ObjectStorePanels)
 | 
			
		||||
        default_panel = 'overview'
 | 
			
		||||
        supports_tenants = True
 | 
			
		||||
        ...
 | 
			
		||||
 | 
			
		||||
    horizon.register(Project)
 | 
			
		||||
 | 
			
		||||
Panel Classes
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
To connect a :class:`~horizon.Panel` with a :class:`~horizon.Dashboard` class
 | 
			
		||||
you register it in a ``panels.py`` file like so::
 | 
			
		||||
 | 
			
		||||
    import horizon
 | 
			
		||||
 | 
			
		||||
    from openstack_dashboard.dashboards.project import dashboard
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class Images(horizon.Panel):
 | 
			
		||||
        name = "Images"
 | 
			
		||||
        slug = 'images'
 | 
			
		||||
        permissions = ('openstack.roles.admin', 'my.other.permission',)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    # You could also register your panel with another application's dashboard
 | 
			
		||||
    dashboard.Project.register(Images)
 | 
			
		||||
 | 
			
		||||
By default a :class:`~horizon.Panel` class looks for a ``urls.py`` file in the
 | 
			
		||||
same directory as ``panel.py`` to include in the rollup of url patterns from
 | 
			
		||||
panels to dashboards to Horizon, resulting in a wholly extensible, configurable
 | 
			
		||||
URL structure.
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
==========================
 | 
			
		||||
Horizon Context Processors
 | 
			
		||||
==========================
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.context_processors
 | 
			
		||||
    :members:
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
==================
 | 
			
		||||
Horizon Decorators
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.decorators
 | 
			
		||||
   :members:
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
==================
 | 
			
		||||
Horizon Exceptions
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.exceptions
 | 
			
		||||
   :members:
 | 
			
		||||
@@ -1,98 +0,0 @@
 | 
			
		||||
=============
 | 
			
		||||
Horizon Forms
 | 
			
		||||
=============
 | 
			
		||||
 | 
			
		||||
Horizon ships with some very useful base form classes, form fields,
 | 
			
		||||
class-based views, and javascript helpers which streamline most of the common
 | 
			
		||||
tasks related to form handling.
 | 
			
		||||
 | 
			
		||||
Form Classes
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.forms.base
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Form Fields
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.forms.fields
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Form Views
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.forms.views
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Forms Javascript
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
Switchable Fields
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
By marking fields with the ``"switchable"`` and ``"switched"`` classes along
 | 
			
		||||
with defining a few data attributes you can programmatically hide, show,
 | 
			
		||||
and rename fields in a form.
 | 
			
		||||
 | 
			
		||||
The triggers are fields using a ``select`` input widget, marked with the
 | 
			
		||||
"switchable" class, and defining a "data-slug" attribute. When they are changed,
 | 
			
		||||
any input with the ``"switched"`` class and defining a ``"data-switch-on"``
 | 
			
		||||
attribute which matches the ``select`` input's ``"data-slug"`` attribute will be
 | 
			
		||||
evaluated for necessary changes. In simpler terms, if the ``"switched"`` target
 | 
			
		||||
input's ``"switch-on"`` matches the ``"slug"`` of the ``"switchable"`` trigger
 | 
			
		||||
input, it gets switched. Simple, right?
 | 
			
		||||
 | 
			
		||||
The ``"switched"`` inputs also need to define states. For each state in which
 | 
			
		||||
the input should be shown, it should define a data attribute like the
 | 
			
		||||
following: ``data-<slug>-<value>="<desired label>"``. When the switch event
 | 
			
		||||
happens the value of the ``"switchable"`` field will be compared to the
 | 
			
		||||
data attributes and the correct label will be applied to the field. If
 | 
			
		||||
a corresponding label for that value is *not* found, the field will
 | 
			
		||||
be hidden instead.
 | 
			
		||||
 | 
			
		||||
A simplified example is as follows::
 | 
			
		||||
 | 
			
		||||
    source = forms.ChoiceField(
 | 
			
		||||
        label=_('Source'),
 | 
			
		||||
        choices=[
 | 
			
		||||
            ('cidr', _('CIDR')),
 | 
			
		||||
            ('sg', _('Security Group'))
 | 
			
		||||
        ],
 | 
			
		||||
        widget=forms.Select(attrs={
 | 
			
		||||
            'class': 'switchable',
 | 
			
		||||
            'data-slug': 'source'
 | 
			
		||||
        })
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    cidr = fields.IPField(
 | 
			
		||||
        label=_("CIDR"),
 | 
			
		||||
        required=False,
 | 
			
		||||
        widget=forms.TextInput(attrs={
 | 
			
		||||
            'class': 'switched',
 | 
			
		||||
            'data-switch-on': 'source',
 | 
			
		||||
            'data-source-cidr': _('CIDR')
 | 
			
		||||
        })
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    security_group = forms.ChoiceField(
 | 
			
		||||
        label=_('Security Group'),
 | 
			
		||||
        required=False,
 | 
			
		||||
        widget=forms.Select(attrs={
 | 
			
		||||
            'class': 'switched',
 | 
			
		||||
            'data-switch-on': 'source',
 | 
			
		||||
            'data-source-sg': _('Security Group')
 | 
			
		||||
        })
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
That code would create the ``"switchable"`` control field ``source``, and the
 | 
			
		||||
two ``"switched"`` fields ``cidr`` and ``security group`` which are hidden or
 | 
			
		||||
shown depending on the value of ``source``.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
NOTE: A field can only safely define one slug in its ``"switch-on"`` attribute.
 | 
			
		||||
While switching on multiple fields is possible, the behavior is very hard to
 | 
			
		||||
predict due to the events being fired from the various switchable fields in
 | 
			
		||||
order. You generally end up just having it hidden most of the time by accident,
 | 
			
		||||
so it's not recommended. Instead just add a second field to the form and control
 | 
			
		||||
the two independently, then merge their results in the form's clean or handle
 | 
			
		||||
methods at the end.
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
======================
 | 
			
		||||
The ``horizon`` Module
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
.. module:: horizon
 | 
			
		||||
 | 
			
		||||
Horizon ships with a single point of contact for hooking into your project if
 | 
			
		||||
you aren't developing your own :class:`~horizon.Dashboard` or
 | 
			
		||||
:class:`~horizon.Panel`::
 | 
			
		||||
 | 
			
		||||
    import horizon
 | 
			
		||||
 | 
			
		||||
From there you can access all the key methods you need.
 | 
			
		||||
 | 
			
		||||
Horizon
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
.. attribute:: urls
 | 
			
		||||
 | 
			
		||||
    The auto-generated URLconf for Horizon. Usage::
 | 
			
		||||
 | 
			
		||||
        url(r'', include(horizon.urls)),
 | 
			
		||||
 | 
			
		||||
.. autofunction:: register
 | 
			
		||||
.. autofunction:: unregister
 | 
			
		||||
.. autofunction:: get_absolute_url
 | 
			
		||||
.. autofunction:: get_user_home
 | 
			
		||||
.. autofunction:: get_dashboard
 | 
			
		||||
.. autofunction:: get_default_dashboard
 | 
			
		||||
.. autofunction:: get_dashboards
 | 
			
		||||
 | 
			
		||||
Dashboard
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Dashboard
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Panel
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Panel
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: PanelGroup
 | 
			
		||||
    :members:
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
==================
 | 
			
		||||
Horizon Middleware
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
.. automodule:: horizon.middleware
 | 
			
		||||
    :members:
 | 
			
		||||
@@ -1,233 +0,0 @@
 | 
			
		||||
===========================
 | 
			
		||||
The ``run_tests.sh`` Script
 | 
			
		||||
===========================
 | 
			
		||||
 | 
			
		||||
.. contents:: Contents:
 | 
			
		||||
   :local:
 | 
			
		||||
 | 
			
		||||
Horizon ships with a script called ``run_tests.sh`` at the root of the
 | 
			
		||||
repository. This script provides many crucial functions for the project,
 | 
			
		||||
and also makes several otherwise complex tasks trivial for you as a
 | 
			
		||||
developer.
 | 
			
		||||
 | 
			
		||||
First Run
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
If you start with a clean copy of the Horizon repository, the first thing
 | 
			
		||||
you should do is to run ``./run_tests.sh`` from the root of the repository.
 | 
			
		||||
This will do two things for you:
 | 
			
		||||
 | 
			
		||||
    #. Set up a virtual environment for both the ``horizon`` module and
 | 
			
		||||
       the ``openstack-dashboard`` project using
 | 
			
		||||
       ``openstack-dashboard/tools/install_venv.py``.
 | 
			
		||||
    #. Run the tests for both ``horizon`` and ``openstack-dashboard`` using
 | 
			
		||||
       their respective environments and verify that evreything is working.
 | 
			
		||||
 | 
			
		||||
Setting up the environment the first time can take several minutes, but only
 | 
			
		||||
needs to be done once. If dependencies are added in the future, updating the
 | 
			
		||||
environments will be necessary but not as time consuming.
 | 
			
		||||
 | 
			
		||||
I just want to run the tests!
 | 
			
		||||
=============================
 | 
			
		||||
 | 
			
		||||
Running the full set of unit tests quickly and easily is the main goal of this
 | 
			
		||||
script. All you need to do is::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh
 | 
			
		||||
 | 
			
		||||
Yep, that's it. However, for a more thorough test run you can include the
 | 
			
		||||
Selenium tests by using the ``--with-selenium`` flag::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --with-selenium
 | 
			
		||||
 | 
			
		||||
If you run horizon in a minimal installation VM, you will probably need
 | 
			
		||||
the following (steps for Fedora 18 minimal installation):
 | 
			
		||||
 | 
			
		||||
    #. Install these packages in the VM:
 | 
			
		||||
       ``yum install xorg-x11-xauth xorg-x11-fonts-Type1.noarch``.
 | 
			
		||||
    #. Install firefox in the VM:
 | 
			
		||||
       ``yum install firefox``.
 | 
			
		||||
    #. Connect to the VM by ``ssh -X``
 | 
			
		||||
       (if you run ``set|grep DISP``, you should see that the DISPLAY is set).
 | 
			
		||||
    #. Run
 | 
			
		||||
       ``./run_tests.sh --with-selenium``.
 | 
			
		||||
 | 
			
		||||
Running a subset of tests
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
Instead of running all tests, you can specify an individual directory, file,
 | 
			
		||||
class, or method that contains test code.
 | 
			
		||||
 | 
			
		||||
To run the tests in the ``horizon/test/tests/tables.py`` file::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh horizon.test.tests.tables
 | 
			
		||||
 | 
			
		||||
To run the tests in the `WorkflowsTests` class in
 | 
			
		||||
``horizon/test/tests/workflows``::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh horizon.test.tests.workflows:WorkflowsTests
 | 
			
		||||
 | 
			
		||||
To run just the `WorkflowsTests.test_workflow_view` test method::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh horizon.test.tests.workflows:WorkflowsTests.test_workflow_view
 | 
			
		||||
 | 
			
		||||
Using Dashboard and Panel Templates
 | 
			
		||||
===================================
 | 
			
		||||
 | 
			
		||||
Horizon has a set of convenient management commands for creating new
 | 
			
		||||
dashboards and panels based on basic templates.
 | 
			
		||||
 | 
			
		||||
Dashboards
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
To create a new dashboard, run the following:
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh -m startdash <dash_name>
 | 
			
		||||
 | 
			
		||||
This will create a directory with the given dashboard name, a ``dashboard.py``
 | 
			
		||||
module with the basic dashboard code filled in, and various other common
 | 
			
		||||
"boilerplate" code.
 | 
			
		||||
 | 
			
		||||
Available options:
 | 
			
		||||
 | 
			
		||||
* --target: the directory in which the dashboard files should be created.
 | 
			
		||||
  Default: A new directory within the current directory.
 | 
			
		||||
 | 
			
		||||
Panels
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
To create a new panel, run the following:
 | 
			
		||||
 | 
			
		||||
    ./run_tests -m startpanel <panel_name> --dashboard=<dashboard_path>
 | 
			
		||||
 | 
			
		||||
This will create a directory with the given panel name, and ``panel.py``
 | 
			
		||||
module with the basic panel code filled in, and various other common
 | 
			
		||||
"boilerplate" code.
 | 
			
		||||
 | 
			
		||||
Available options:
 | 
			
		||||
 | 
			
		||||
* -d, --dashboard: The dotted python path to your dashboard app (the module
 | 
			
		||||
  which containers the ``dashboard.py`` file.).
 | 
			
		||||
* --target: the directory in which the panel files should be created.
 | 
			
		||||
  If the value is ``auto`` the panel will be created as a new directory inside
 | 
			
		||||
  the dashboard module's directory structure. Default: A new directory within
 | 
			
		||||
  the current directory.
 | 
			
		||||
 | 
			
		||||
Give me metrics!
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
You can generate various reports and metrics using command line arguments
 | 
			
		||||
to ``run_tests.sh``.
 | 
			
		||||
 | 
			
		||||
Coverage
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
To run coverage reports::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --coverage
 | 
			
		||||
 | 
			
		||||
The reports are saved to ``./reports/`` and ``./coverage.xml``.
 | 
			
		||||
 | 
			
		||||
PEP8
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
You can check for PEP8 violations as well::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --pep8
 | 
			
		||||
 | 
			
		||||
The results are saved to ``./pep8.txt``.
 | 
			
		||||
 | 
			
		||||
PyLint
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
For more detailed code analysis you can run::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --pylint
 | 
			
		||||
 | 
			
		||||
The output will be saved in ``./pylint.txt``.
 | 
			
		||||
 | 
			
		||||
Tab Characters
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
For those who dislike having a mix of tab characters and spaces for indentation
 | 
			
		||||
there's a command to check for that in Python, CSS, JavaScript and HTML files::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --tabs
 | 
			
		||||
 | 
			
		||||
This will output a total "tab count" and a list of the offending files.
 | 
			
		||||
 | 
			
		||||
Running the development server
 | 
			
		||||
==============================
 | 
			
		||||
 | 
			
		||||
As an added bonus, you can run Django's development server directly from
 | 
			
		||||
the root of the repository with ``run_tests.sh`` like so::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --runserver
 | 
			
		||||
 | 
			
		||||
This is effectively just an alias for::
 | 
			
		||||
 | 
			
		||||
    ./openstack-dashboard/tools/with_venv.sh ./openstack-dashboard/dashboard/manage.py runserver
 | 
			
		||||
 | 
			
		||||
Generating the documentation
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
You can build Horizon's documentation automatically by running::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --docs
 | 
			
		||||
 | 
			
		||||
The output is stored in ``./doc/build/html/``.
 | 
			
		||||
 | 
			
		||||
Updating the translation files
 | 
			
		||||
==============================
 | 
			
		||||
 | 
			
		||||
You can update all of the translation files for both the ``horizon`` app and
 | 
			
		||||
``openstack_dashboard`` project with a single command:
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --makemessages
 | 
			
		||||
 | 
			
		||||
or, more compactly:
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --m
 | 
			
		||||
 | 
			
		||||
Starting clean
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
If you ever want to start clean with a new environment for Horizon, you can
 | 
			
		||||
run::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --force
 | 
			
		||||
 | 
			
		||||
That will blow away the existing environments and create new ones for you.
 | 
			
		||||
 | 
			
		||||
Non-interactive Mode
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
There is an optional flag which will run the script in a non-interactive
 | 
			
		||||
(and eventually less verbose) mode::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --quiet
 | 
			
		||||
 | 
			
		||||
This will automatically take the default action for actions which would
 | 
			
		||||
normally prompt for user input such as installing/updating the environment.
 | 
			
		||||
 | 
			
		||||
Environment Backups
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
To speed up the process of doing clean checkouts, running continuous
 | 
			
		||||
integration tests, etc. there are options for backing up the current
 | 
			
		||||
environment and restoring from a backup.
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh --restore-environment
 | 
			
		||||
    ./run_tests.sh --backup-environment
 | 
			
		||||
 | 
			
		||||
The environment backup is stored in ``/tmp/.horizon_environment/``.
 | 
			
		||||
 | 
			
		||||
Environment Versioning
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
Horizon keeps track of changes to the environment by incrementing an
 | 
			
		||||
``environment_version`` integer at the top of ``run_tests.sh``.
 | 
			
		||||
 | 
			
		||||
If you do anything which changes the environment (adding new dependencies
 | 
			
		||||
or renaming directories are both great examples) be sure to increment the
 | 
			
		||||
``environment_version`` counter as well.
 | 
			
		||||
@@ -1,82 +0,0 @@
 | 
			
		||||
==================
 | 
			
		||||
Horizon DataTables
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
.. module:: horizon.tables
 | 
			
		||||
 | 
			
		||||
Horizon includes a componentized API for programmatically creating tables
 | 
			
		||||
in the UI. Why would you want this? It means that every table renders
 | 
			
		||||
correctly and consistently, table- and row-level actions all have a consistent
 | 
			
		||||
API and appearance, and generally you don't have to reinvent the wheel or
 | 
			
		||||
copy-and-paste every time you need a new table!
 | 
			
		||||
 | 
			
		||||
DataTable
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
The core class which defines the high-level structure of the table being
 | 
			
		||||
represented. Example::
 | 
			
		||||
 | 
			
		||||
    class MyTable(DataTable):
 | 
			
		||||
        name = Column('name')
 | 
			
		||||
        email = Column('email')
 | 
			
		||||
 | 
			
		||||
        class Meta:
 | 
			
		||||
            name = "my_table"
 | 
			
		||||
            table_actions = (MyAction, MyOtherAction)
 | 
			
		||||
            row_actions - (MyAction)
 | 
			
		||||
 | 
			
		||||
A full reference is included below:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: DataTable
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
DataTable Options
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
The following options can be defined in a ``Meta`` class inside a
 | 
			
		||||
:class:`.DataTable` class. Example::
 | 
			
		||||
 | 
			
		||||
    class MyTable(DataTable):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            name = "my_table"
 | 
			
		||||
            verbose_name = "My Table"
 | 
			
		||||
 | 
			
		||||
.. autoclass:: horizon.tables.base.DataTableOptions
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Table Components
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Column
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Row
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Actions
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Action
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: LinkAction
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: FilterAction
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: BatchAction
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: DeleteAction
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Class-Based Views
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
Several class-based views are provided to make working with DataTables
 | 
			
		||||
easier in your UI.
 | 
			
		||||
 | 
			
		||||
.. autoclass:: DataTableView
 | 
			
		||||
 | 
			
		||||
.. autoclass:: MultiTableView
 | 
			
		||||
@@ -1,45 +0,0 @@
 | 
			
		||||
==========================
 | 
			
		||||
Horizon Tabs and TabGroups
 | 
			
		||||
==========================
 | 
			
		||||
 | 
			
		||||
.. module:: horizon.tabs
 | 
			
		||||
 | 
			
		||||
Horizon includes a set of reusable components for programmatically
 | 
			
		||||
building tabbed interfaces with fancy features like dynamic AJAX loading
 | 
			
		||||
and nearly effortless templating and styling.
 | 
			
		||||
 | 
			
		||||
Tab Groups
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
For any tabbed interface, your fundamental element is the tab group which
 | 
			
		||||
contains all your tabs. This class provides a dead-simple API for building
 | 
			
		||||
tab groups and encapsulates all the necessary logic behind the scenes.
 | 
			
		||||
 | 
			
		||||
.. autoclass:: TabGroup
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Tabs
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
The tab itself is the discrete unit for a tab group, representing one
 | 
			
		||||
view of data.
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Tab
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: TableTab
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TabView
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
There is also a useful and simple generic class-based view for handling
 | 
			
		||||
the display of a :class:`~horizon.tabs.TabGroup` class.
 | 
			
		||||
 | 
			
		||||
.. autoclass:: TabView
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: TabbedTableView
 | 
			
		||||
    :members:
 | 
			
		||||
@@ -1,25 +0,0 @@
 | 
			
		||||
========================
 | 
			
		||||
Horizon TestCase Classes
 | 
			
		||||
========================
 | 
			
		||||
 | 
			
		||||
.. module:: horizon.test.helpers
 | 
			
		||||
 | 
			
		||||
Horizon provides a base test case class which provides several useful
 | 
			
		||||
pre-prepared attributes for testing Horizon components.
 | 
			
		||||
 | 
			
		||||
.. autoclass:: TestCase
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. module :: openstack_dashboard.test.helpers
 | 
			
		||||
 | 
			
		||||
The OpenStack Dashboard also provides test case classes for greater
 | 
			
		||||
ease-of-use when testing APIs and OpenStack-specific auth scenarios.
 | 
			
		||||
 | 
			
		||||
.. autoclass:: TestCase
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: APITestCase
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
.. autoclass:: BaseAdminViewTests
 | 
			
		||||
    :members:
 | 
			
		||||
@@ -1,33 +0,0 @@
 | 
			
		||||
=================
 | 
			
		||||
Horizon Workflows
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
.. module:: horizon.workflows
 | 
			
		||||
 | 
			
		||||
One of the most challenging aspects of building a compelling user experience
 | 
			
		||||
is crafting complex multi-part workflows. Horizon's ``workflows`` module
 | 
			
		||||
aims to bring that capability within everyday reach.
 | 
			
		||||
 | 
			
		||||
Workflows
 | 
			
		||||
=========
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Workflow
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Steps
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Step
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
Actions
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
.. autoclass:: Action
 | 
			
		||||
    :members:
 | 
			
		||||
 | 
			
		||||
WorkflowView
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
.. autoclass:: WorkflowView
 | 
			
		||||
    :members:
 | 
			
		||||
@@ -1,148 +0,0 @@
 | 
			
		||||
======================
 | 
			
		||||
Horizon 2012.1 "Essex"
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
Release Overview
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
During the Essex release cycle, Horizon underwent a significant set of internal
 | 
			
		||||
changes to allow extensibility and customization while also adding a significant
 | 
			
		||||
number of new features and bringing much greater stability to every interaction
 | 
			
		||||
with the underlying components.
 | 
			
		||||
 | 
			
		||||
Highlights
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
Extensibility
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Making Horizon extensible for third-party developers was one of the core
 | 
			
		||||
goals for the Essex release cycle. Massive strides have been made to allow
 | 
			
		||||
for the addition of new "plug-in" components and customization of OpenStack
 | 
			
		||||
Dashboard deployments.
 | 
			
		||||
 | 
			
		||||
To support this extensability, all the components used to build on Horizon's
 | 
			
		||||
interface are now modular and reusable. Horizon's own dashboards use these
 | 
			
		||||
components, and they have all been built with third-party developers in mind.
 | 
			
		||||
Some of the main components are listed below.
 | 
			
		||||
 | 
			
		||||
Dashboards and Panels
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Horizon's structure has been divided into logical groupings called dashboards
 | 
			
		||||
and panels. Horizon's classes representing these concepts handle all the
 | 
			
		||||
structural concerns associated with building a complete user interface
 | 
			
		||||
(navigation, access control, url structure, etc.).
 | 
			
		||||
 | 
			
		||||
Data Tables
 | 
			
		||||
~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
One of the most common activities in a dashboard user interface is simply
 | 
			
		||||
displaying a list of resources or data and allowing the user to take actions on
 | 
			
		||||
that data. To this end, Horizon abstracted the commonalities of this task into a
 | 
			
		||||
reusable set of classes which allow developers to programmatically create
 | 
			
		||||
displays and interactions for their data with minimal effort and zero
 | 
			
		||||
boilerplate.
 | 
			
		||||
 | 
			
		||||
Tabs and TabGroups
 | 
			
		||||
~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Another extremely common user-interface element is the use of "tabs" to break
 | 
			
		||||
down discrete groups of data into manageable chunks. Since these tabs often
 | 
			
		||||
encompasse vastly different data, may have completely different access
 | 
			
		||||
restrictions, and may sometimes be better-off being loaded dynamically rather
 | 
			
		||||
than with the initial page load, Horizon includes tab and tab group classes for
 | 
			
		||||
constructing these interfaces elegently and with no knowledge of the HTML, CSS
 | 
			
		||||
or JavaScript involved.
 | 
			
		||||
 | 
			
		||||
Nova Features
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Support for Nova's features has been greatly improved in Essex:
 | 
			
		||||
 | 
			
		||||
* Support for Nova volumes, including:
 | 
			
		||||
    * Volumes creation and management.
 | 
			
		||||
    * Volume snapshots.
 | 
			
		||||
    * Realtime AJAX updating for volumes in transition states.
 | 
			
		||||
* Improved Nova instance display and interactions, including:
 | 
			
		||||
    * Launching instances from volumes.
 | 
			
		||||
    * Pausing/suspending instances.
 | 
			
		||||
    * Displaying instance power states.
 | 
			
		||||
    * Realtime AJAX updating for instances in transition states.
 | 
			
		||||
* Support for managing Floating IP address pools.
 | 
			
		||||
* New instance and volume detail views.
 | 
			
		||||
 | 
			
		||||
Settings
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
A new "Settings" area was added that offers several userful functions:
 | 
			
		||||
 | 
			
		||||
* EC2 credentials download.
 | 
			
		||||
* OpenStack RC file download.
 | 
			
		||||
* User language preference customization.
 | 
			
		||||
 | 
			
		||||
User Experience Improvements
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
* Support for batch actions on multiple resources (e.g. terminating multiple
 | 
			
		||||
  instances at once).
 | 
			
		||||
* Modal interactions throughout the entire UI.
 | 
			
		||||
* AJAX form submission for in-place validation.
 | 
			
		||||
* Improved in-context help for forms (tooltips and validation messages).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Community
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
* Creation and publication of a set of Human Interface Guidelines (HIG).
 | 
			
		||||
* Copious amounts of documentation for developers.
 | 
			
		||||
 | 
			
		||||
Under The Hood
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
* Internationalization fully enabled, with all strings marked for translation.
 | 
			
		||||
* Client library changes:
 | 
			
		||||
    * Full migration to python-novaclient from the deprecated openstackx library.
 | 
			
		||||
    * Migration to python-keystoneclient from the deprecated keystone portion
 | 
			
		||||
      of the python-novaclient library.
 | 
			
		||||
* Client-side templating capabilities for more easily creating dynamic
 | 
			
		||||
  interactions.
 | 
			
		||||
* Frontend overhaul to use the Bootstrap CSS/JS framework.
 | 
			
		||||
* Centralized error handling for vastly improved stability/reliability
 | 
			
		||||
  across APIs/clients.
 | 
			
		||||
* Completely revamped test suite with comprehensive test data.
 | 
			
		||||
* Forward-compatibility with Django 1.4 and the option of cookie-based sessions.
 | 
			
		||||
 | 
			
		||||
Known Issues and Limitations
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
Quantum
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Quantum support has been removed from Horizon for the Essex release. It will be
 | 
			
		||||
restored in Folsom in conjunction with Quantum's first release as a core
 | 
			
		||||
OpenStack project.
 | 
			
		||||
 | 
			
		||||
Keystone
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
Due to the mechanisms by which Keystone determines "admin"-ness for a user, an
 | 
			
		||||
admin user interacting with the "Project" dashboard may see some inconsistent
 | 
			
		||||
behavior such as all resources being listed instead of only those belonging to
 | 
			
		||||
that project, or only being able to return to the "Admin" dashboard while
 | 
			
		||||
accessing certain projects.
 | 
			
		||||
 | 
			
		||||
Exceptions during customization
 | 
			
		||||
-------------------------------
 | 
			
		||||
 | 
			
		||||
Exceptions raised while overriding built-in Horizon behavior via the
 | 
			
		||||
"customization_module" setting may trigger a bug in the error handling
 | 
			
		||||
which will mask the original exception.
 | 
			
		||||
 | 
			
		||||
Backwards Compatibility
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
The Essex Horizon release is only partially backwards-compatible with Diablo
 | 
			
		||||
OpenStack components. While it is largely possible to log in and interact, many
 | 
			
		||||
functions in Nova, Glance and Keystone changed too substantially in Essex to
 | 
			
		||||
maintain full compatibliity.
 | 
			
		||||
@@ -1,159 +0,0 @@
 | 
			
		||||
=======================
 | 
			
		||||
Horizon 2012.2 "Folsom"
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
Release Overview
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
The Folsom release cycle brought several major advances to Horizon's user
 | 
			
		||||
experience while also reintroducing Quantum networking as a core piece
 | 
			
		||||
of the OpenStack Dashboard.
 | 
			
		||||
 | 
			
		||||
Highlights
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
Networking (Quantum)
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
With Quantum being a core project for the Folsom release, we worked closely
 | 
			
		||||
with the Quantum team to bring networking support back into Horizon. This
 | 
			
		||||
appears in two primary places: the Networks panel in both the Project and
 | 
			
		||||
Admin dashboards, and the Network tab in the Launch Instance workflow. Expect
 | 
			
		||||
further improvements in these areas as Quantum continues to mature and more
 | 
			
		||||
users adopt this model of virtual network management.
 | 
			
		||||
 | 
			
		||||
User Experience
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
Workflows
 | 
			
		||||
~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
By far the biggest UI/UX change in the Folsom release is the introduction of
 | 
			
		||||
programmatic workflows. These components allow developers to create concise
 | 
			
		||||
interactions that combine discrete tasks spanning multiple services and
 | 
			
		||||
resources in a user-friendly way and with minimal boilerplate code. Within
 | 
			
		||||
a workflow, related objects can also be dynamically created so users don't lose
 | 
			
		||||
their place when they realize the item they wanted isn't currently available.
 | 
			
		||||
Look for examples of these workflows in Launch Instance, Associate Floating IP,
 | 
			
		||||
and Create/Edit Project.
 | 
			
		||||
 | 
			
		||||
Resource Browser
 | 
			
		||||
~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Another cool new component is an interface designed for "browsing" resources
 | 
			
		||||
which are nested under a parent resource. The object store (Swift) is a prime
 | 
			
		||||
example of this. Now there is a consistent top-level navigation for containers
 | 
			
		||||
on the left-hand pane of the "browser" while the right-hand pane lets you
 | 
			
		||||
explore within those containers and sub-folders.
 | 
			
		||||
 | 
			
		||||
User Experience Improvements
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
* Timezone support is now enabled. You can select your preferred timezone
 | 
			
		||||
  in the User Settings panel.
 | 
			
		||||
 | 
			
		||||
Community
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
* Third-party developers who wish to build on Horizon can get started much
 | 
			
		||||
  faster using the new dashboard and panel templates. See the docs on
 | 
			
		||||
  `creating a dashboard`_ and `creating a panel`_ for more information.
 | 
			
		||||
 | 
			
		||||
* A `thorough set of documentation`_ for developers on how to go about
 | 
			
		||||
  internationalizing, localizing and translating OpenStack projects
 | 
			
		||||
  is now available.
 | 
			
		||||
 | 
			
		||||
.. _creating a dashboard: http://docs.openstack.org/developer/horizon/topics/tutorial.html#creating-a-dashboard
 | 
			
		||||
.. _creating a panel: http://docs.openstack.org/developer/horizon/topics/tutorial.html#creating-a-panel
 | 
			
		||||
.. _thorough set of documentation: http://wiki.openstack.org/Translations
 | 
			
		||||
 | 
			
		||||
Under The Hood
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
* The python-swiftclient library and python-cinderclient libraries are now
 | 
			
		||||
  used under the hood instead of cloudfiles and python-novaclient respectively.
 | 
			
		||||
 | 
			
		||||
* Internationalization of client-side JavaScript is now possible in addition
 | 
			
		||||
  to server-side Python code.
 | 
			
		||||
 | 
			
		||||
* Keystone authentication is now handled by a proper pluggable Django
 | 
			
		||||
  authentication backend, offering significantly better and more reliable
 | 
			
		||||
  security for Horizon.
 | 
			
		||||
 | 
			
		||||
Other Improvements and Fixes
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
Some of the general areas of improvement include:
 | 
			
		||||
 | 
			
		||||
* Images can now be added to Glance by providing a URL for Glance to download
 | 
			
		||||
  the image data from.
 | 
			
		||||
 | 
			
		||||
* Quotas are now displayed dynamically throughout the Project dashboard.
 | 
			
		||||
 | 
			
		||||
* API endpoints are now displayed on the OpenStack RC File panel so they
 | 
			
		||||
  can be organically discovered by an end-user.
 | 
			
		||||
 | 
			
		||||
* DataTables now support a summation row at the bottom of the table.
 | 
			
		||||
 | 
			
		||||
* Better cross-browser support (Safari and IE particularly).
 | 
			
		||||
 | 
			
		||||
* Fewer API calls to OpenStack endpoints (improves performance).
 | 
			
		||||
 | 
			
		||||
* Better validation of what actions are permitted when.
 | 
			
		||||
 | 
			
		||||
* Improved error handling and error messages.
 | 
			
		||||
 | 
			
		||||
Known Issues and Limitations
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
Floating IPs and Quantum
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
Due to the very late addition of floating IP support in Quantum, Nova's
 | 
			
		||||
integration there is lacking, so floating IP-related API calls to Nova will
 | 
			
		||||
fail when your OpenStack deployment uses Quantum for networking. This means
 | 
			
		||||
that Horizon actions such as "allocate" and "associate" floating IPs will
 | 
			
		||||
not work either since they rely on the underlying APIs.
 | 
			
		||||
 | 
			
		||||
Pagination
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
A number of the "index" pages don't fully work with API pagination yet,
 | 
			
		||||
causing them to only display the first chunk of results returned by the API.
 | 
			
		||||
This number is often 1000 (as in the case of novaclient results), but does vary
 | 
			
		||||
somewhat.
 | 
			
		||||
 | 
			
		||||
Deleting large numbers of resources simultaneously
 | 
			
		||||
--------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Using the "select all" checkbox to delete large numbers of resources via the
 | 
			
		||||
API can cause network timeouts (depending on configuration). This is
 | 
			
		||||
due to the APIs not supporting bulk-deletion natively, and consequently Horizon
 | 
			
		||||
has to send requests to delete each resource individually behind the scenes.
 | 
			
		||||
 | 
			
		||||
Backwards Compatibility
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
The Folsom Horizon release should be fully-compatible with both Folsom and
 | 
			
		||||
Essex versions of the rest of the OpenStack core projects (Nova, Swift, etc.).
 | 
			
		||||
While some features work significantly better with an all-Folsom stack due
 | 
			
		||||
to bugfixes, etc. in underlying services, there should not be any limitations
 | 
			
		||||
on what will or will not function. (Note: Quantum was not a core OpenStack
 | 
			
		||||
project in Essex, and thus this statement does not apply to network management.)
 | 
			
		||||
 | 
			
		||||
In terms of APIs provided for extending Horizon, there are a handful of
 | 
			
		||||
backwards-incompatible changes that were made:
 | 
			
		||||
 | 
			
		||||
* The ``can_haz`` and ``can_haz_list`` template filters have been renamed
 | 
			
		||||
  to ``has_permissions`` and ``has_permissions_on_list`` respectively.
 | 
			
		||||
 | 
			
		||||
* The dashboard-specific ``base.html`` templates (e.g. ``nova/base.html``,
 | 
			
		||||
  ``syspanel/base.html``, etc.) have been removed in favor of a single
 | 
			
		||||
  ``base.html`` template.
 | 
			
		||||
 | 
			
		||||
* In conjunction with the previous item, the dashboard-specific template blocks
 | 
			
		||||
  (e.g. ``nova_main``, ``syspanel_main``, etc.) have been removed in favor of
 | 
			
		||||
  a single ``main`` template block.
 | 
			
		||||
 | 
			
		||||
Overall, though, great effort has been made to maintain compatibility for
 | 
			
		||||
third-party developers who may have built on Horizon so far.
 | 
			
		||||
@@ -1,274 +0,0 @@
 | 
			
		||||
========================
 | 
			
		||||
Horizon 2013.1 "Grizzly"
 | 
			
		||||
========================
 | 
			
		||||
 | 
			
		||||
Release Overview
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
The Grizzly release cycle saw sweeping improvements to overall user experience,
 | 
			
		||||
huge stability improvements, lots of new networking, instance management and
 | 
			
		||||
image management features, a long-needed architectural clarification, and big
 | 
			
		||||
increases in community engagement! Read on to get the specifics.
 | 
			
		||||
 | 
			
		||||
Highlights
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
New Features
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Networking
 | 
			
		||||
~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Quantum added a huge number of new features in Grizzly, including L3 support
 | 
			
		||||
(routers), load balancers, network topology infographics, better compatibility
 | 
			
		||||
with Nova networking APIs (VNIC ordering when launching an instance; security
 | 
			
		||||
groups and floating IP integration) and vastly improved informational displays.
 | 
			
		||||
 | 
			
		||||
Direct Image Upload To Glance
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
It is now possible (though there are numerous deployment/security implications)
 | 
			
		||||
to upload an image file directly from a user's hard disk to Glance through
 | 
			
		||||
Horizon. For multi-GB images it is still strongly recommended that the upload
 | 
			
		||||
be done using the Glance CLI. Further improvements to this feature will come in
 | 
			
		||||
future releases.
 | 
			
		||||
 | 
			
		||||
Flavor Extra Specs Support
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
In Folsom, Nova added support for "extra specs" on flavors--additional metadata
 | 
			
		||||
which custom schedulers could use for appropriately scheduling instances. As of
 | 
			
		||||
the Grizzly release, Horizon now supports reading and writing that data on any
 | 
			
		||||
flavor.
 | 
			
		||||
 | 
			
		||||
Migrate Instance
 | 
			
		||||
~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Administrators now have the ability to migrate an instance off of its current
 | 
			
		||||
host via the Admin dashboard's Instances panel.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
User Experience Improvements
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
"Not Authorized" & Being Logged Out
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
A shocking number of the problems first-time deployers of OpenStack have can be
 | 
			
		||||
summarized as "I thought I set everything up, then I tried to log into the
 | 
			
		||||
dashboard and I was immediately logged back out." The root cause of this was
 | 
			
		||||
that in an effort to be as secure as possible any 401 or 403 response from
 | 
			
		||||
any service API was being treated the same as if it was an attempt to access
 | 
			
		||||
an unauthorized portion of Horizon, and the user was summarily logged out with
 | 
			
		||||
little to no information as to why.
 | 
			
		||||
 | 
			
		||||
In Grizzly we have instead chosen to improve this by treating service API
 | 
			
		||||
401 and 403 errors as slightly less severe than unauthorized access attempts
 | 
			
		||||
to resitricted areas of Horizon. The reason for this is threefold:
 | 
			
		||||
 | 
			
		||||
#. For a non-malicious user these errors are almost 100% the result of
 | 
			
		||||
   misconfiguration and this makes debugging possible.
 | 
			
		||||
#. A malicious user can make the exact same "unauthorized" requests via the
 | 
			
		||||
   CLI as they can via the dashboard; no special privileges are granted.
 | 
			
		||||
#. API errors are generated by external systems not under the purview of our
 | 
			
		||||
   project and while we should attempt to respect and take appropriate action
 | 
			
		||||
   on those errors, we should not do anything drastic or even potentially
 | 
			
		||||
   destructive because of them.
 | 
			
		||||
 | 
			
		||||
Going forward the user will not be logged out, but no information will be
 | 
			
		||||
populated on the page and they will be presented with error messages informing
 | 
			
		||||
them that they are unauthorized for the data they attempted to access.
 | 
			
		||||
 | 
			
		||||
Reorganizations
 | 
			
		||||
~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
A couple of long-standing user confusions were fixed in Grizzly.
 | 
			
		||||
 | 
			
		||||
First off, the API Access panel (containing a user's API endpoints, rc files,
 | 
			
		||||
and EC2 credentials) was moved from Settings to the Access & Security section
 | 
			
		||||
of the Project dashboard.
 | 
			
		||||
 | 
			
		||||
Second, the Default Quotas and Services panels (which were both strictly
 | 
			
		||||
informational) were combined into tabs in a single System Info panel to make
 | 
			
		||||
it clear that these panels are thematically related, and to create a home for
 | 
			
		||||
informational-only displays like these.
 | 
			
		||||
 | 
			
		||||
One-click Floating IP Management
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
A common complaint from users was that associating a floating IP to an
 | 
			
		||||
instance involved numerous clicks and form selections for something that
 | 
			
		||||
the majority of users had no knowledge of and didn't care about. As such, a
 | 
			
		||||
one-click "simple" floating IP association option has been created. For
 | 
			
		||||
deployments which only have a single floating IP pool, this allows users to
 | 
			
		||||
ignore explicit floating IP management and just click a button to associate
 | 
			
		||||
or disassociate a floating IP with an instance.
 | 
			
		||||
 | 
			
		||||
Organized Images
 | 
			
		||||
~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
The Images table now has a new feature: predefined filters for seeing your own
 | 
			
		||||
images, images that have been shared with you, or public images. This makes
 | 
			
		||||
finding the image you're looking for a great deal easier and more pleasant.
 | 
			
		||||
 | 
			
		||||
Security Group Rule Editing Improvements
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
The security group rule editing experience has always been inherently very
 | 
			
		||||
complicated simply given the number of options and the very technical terms
 | 
			
		||||
involved. Moreover, the combined table-plus-form approach the OpenStack
 | 
			
		||||
Dashboard had taken only made the UX more frustrating for an already difficult
 | 
			
		||||
area.
 | 
			
		||||
 | 
			
		||||
In Grizzly this has all been reworked to be signficantly simpler, and to
 | 
			
		||||
provide as much contextual help and streamlining as possible.
 | 
			
		||||
 | 
			
		||||
Icons!
 | 
			
		||||
~~~~~~
 | 
			
		||||
 | 
			
		||||
In an effort to make the dashboard more at-a-glance usable, we've added icons
 | 
			
		||||
to most of the common action buttons throughout the dashboard.
 | 
			
		||||
 | 
			
		||||
"More Actions", More Better
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Lots of feedback came in that the "more actions" dropdown menu (for tables with
 | 
			
		||||
numerous actions available on each row) was confusing to new users and/or
 | 
			
		||||
difficult to click.
 | 
			
		||||
 | 
			
		||||
We've now improved it so that the button to open the menu is clearly labeled
 | 
			
		||||
and the hitbox for clicking it is significantly larger.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Community
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
Docs, docs, and more docs!
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Large amounts of new documentation was added during the Grizzly cycle, most
 | 
			
		||||
notably are sections documenting: all of the available settings for Horizon and
 | 
			
		||||
the OpenStack Dashboard; security and deployment considerations; and deeper
 | 
			
		||||
guides on customizing the OpenStack Dashboard.
 | 
			
		||||
 | 
			
		||||
IRC Meeting
 | 
			
		||||
~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
During the Grizzly cycle we started holding a weekly project meeting on IRC.
 | 
			
		||||
This has been extremely beneficial for the growth and progress of the project.
 | 
			
		||||
Check out the `OpenStack Meetings wiki page`_ for specifics.
 | 
			
		||||
 | 
			
		||||
.. _Openstack Meetings wiki page: https://wiki.openstack.org/wiki/Meetings#Horizon_team_meeting
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Under The Hood
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
Legacy Dashboard Names & Code Separation
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Very early in the Grizzly cycle we took the opportunity to do some longstanding
 | 
			
		||||
cleanup and refactoring work. The "nova" dashboard was renamed to "project" and
 | 
			
		||||
the "syspanel" dashboard was renamed to "admin" to better reflect their
 | 
			
		||||
respective purposes.
 | 
			
		||||
 | 
			
		||||
Moreover, a better separation was created between code related to the core
 | 
			
		||||
Horizon framework code (which is not related to OpenStack specifically) and
 | 
			
		||||
the OpenStack Dashboard code. At this point *all* code related to OpenStack
 | 
			
		||||
lives in the OpenStack Dashboard directory, while the Horizon framework is
 | 
			
		||||
completely agnostic and is a reusable Django app.
 | 
			
		||||
 | 
			
		||||
Object Storage Delimiters and Pseudo-folder Objects
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
When Horizon's object storage interface was first added, Swift's documentation
 | 
			
		||||
recommended adding 0-byte objects with a special content type to denote
 | 
			
		||||
pseudo-folders within a container. They have since decided that this is not the
 | 
			
		||||
recommended practice, and that pseudo-folders should only be demarcated by
 | 
			
		||||
a delimiting character (usually "/") in the object name.
 | 
			
		||||
 | 
			
		||||
Horizon has been updated under the hood to use this method, which should bring
 | 
			
		||||
it better into line with how most deployments are using their object storage.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Other Improvements and Fixes
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
* Support for Keystone's PKI tokens.
 | 
			
		||||
 | 
			
		||||
* Flavor editing was made significantly more stable.
 | 
			
		||||
 | 
			
		||||
* Security groups can be added to a running instance.
 | 
			
		||||
 | 
			
		||||
* Volume quotas are handled by the appopriate service depending on whether
 | 
			
		||||
  or not Cinder is enabled.
 | 
			
		||||
 | 
			
		||||
* Password confirmation boxes are now validated for matching passwords on
 | 
			
		||||
  the client side for more immediate feedback.
 | 
			
		||||
 | 
			
		||||
* Numerous fixes to display more and better information for instances and
 | 
			
		||||
  volumes in their overview pages.
 | 
			
		||||
 | 
			
		||||
* Improved unicode support for the Object Storage panels.
 | 
			
		||||
 | 
			
		||||
* Logout now attempts to delete the token(s) associated with the current
 | 
			
		||||
  session to avoid replay attacks, etc.
 | 
			
		||||
 | 
			
		||||
* Various fixes for browser compatibility and rendering.
 | 
			
		||||
 | 
			
		||||
* Many, many other bugfixes and improvements. Check out Launchpad for the full
 | 
			
		||||
  list of what went on in Grizzly.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Known Issues and Limitations
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
Editing a Flavor Which Results In An API Error Will Delete The Flavor
 | 
			
		||||
---------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Due to the way that Nova handles flavor editing/replacement it is necessary
 | 
			
		||||
to delete the old flavor before creating the replacement flavor. As such,
 | 
			
		||||
if an API error occurs while creating the replacement it is possible to
 | 
			
		||||
lose the old flavor without the new one being created.
 | 
			
		||||
 | 
			
		||||
Creating Rich Network Topologies
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
Due to several Quantum features landing very late in the Grizzly cycle, it
 | 
			
		||||
is not possible to create particularly complex networking configurations
 | 
			
		||||
through the OpenStack Dashboard. These features will continue to grow
 | 
			
		||||
throughout future releases.
 | 
			
		||||
 | 
			
		||||
Loadbalancer Feature
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
The Loadbalancer feature landed in the 11th hour for both Quantum and Horizon
 | 
			
		||||
and, though we did our best to test it, may still contain undiscovered bugs. It
 | 
			
		||||
is best considered a "beta" or "experimental" feature for the Grizzly release.
 | 
			
		||||
 | 
			
		||||
Quantum Brocade Plugin Not Compatible
 | 
			
		||||
-------------------------------------
 | 
			
		||||
 | 
			
		||||
The Brocade plugin for Quantum does not support key features of the floating
 | 
			
		||||
IP addresses API which are considered central to Horizon's functionality. As
 | 
			
		||||
such, it is not compatible with the Grizzly release's Quantum integration.
 | 
			
		||||
 | 
			
		||||
Deleting large numbers of resources simultaneously
 | 
			
		||||
--------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Using the "select all" checkbox to delete large numbers of resources via the
 | 
			
		||||
API can cause network timeouts (depending on configuration). This is
 | 
			
		||||
due to the APIs not supporting bulk-deletion natively, and consequently Horizon
 | 
			
		||||
has to send requests to delete each resource individually behind the scenes.
 | 
			
		||||
 | 
			
		||||
Backwards Compatibility
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
The Grizzly Horizon release should be fully compatible with both Grizzly and
 | 
			
		||||
Folsom versions of the rest of the OpenStack core projects (Nova, Swift, etc.).
 | 
			
		||||
While some features work significantly better with an all-Grizzly stack due
 | 
			
		||||
to bugfixes, etc. in underlying services, there should not be limitations
 | 
			
		||||
on what will or will not function.
 | 
			
		||||
 | 
			
		||||
Overall, great effort has been made to maintain compatibility for
 | 
			
		||||
third-party developers who may have built on Horizon so far.
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
=======================
 | 
			
		||||
Horizon's tests and you
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
How to run the tests
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
Because Horizon is composed of both the ``horizon`` app and the
 | 
			
		||||
``openstack-dashboard`` reference project, there are in fact two sets of unit
 | 
			
		||||
tests. While they can be run individually without problem, there is an easier
 | 
			
		||||
way:
 | 
			
		||||
 | 
			
		||||
Included at the root of the repository is the ``run_tests.sh`` script
 | 
			
		||||
which invokes both sets of tests, and  optionally generates analyses on both
 | 
			
		||||
components in the process. This script is what what Jenkins uses to verify the
 | 
			
		||||
stability of the project, so you should make sure you run it and it passes
 | 
			
		||||
before you submit any pull requests/patches.
 | 
			
		||||
 | 
			
		||||
To run the tests::
 | 
			
		||||
 | 
			
		||||
    $ ./run_tests.sh
 | 
			
		||||
   
 | 
			
		||||
It's also possible to :doc:`run a subset of unit tests<ref/run_tests>`.
 | 
			
		||||
 | 
			
		||||
.. seealso::
 | 
			
		||||
 | 
			
		||||
    :doc:`ref/run_tests`
 | 
			
		||||
        Full reference for the ``run_tests.sh`` script.
 | 
			
		||||
 | 
			
		||||
Writing tests
 | 
			
		||||
=============
 | 
			
		||||
 | 
			
		||||
Horizon uses Django's unit test machinery (which extends Python's ``unittest2``
 | 
			
		||||
library) as the core of its test suite. As such, all tests for the Python code
 | 
			
		||||
should be written as unit tests. No doctests please.
 | 
			
		||||
 | 
			
		||||
In general new code without unit tests will not be accepted, and every bugfix
 | 
			
		||||
*must* include a regression test.
 | 
			
		||||
 | 
			
		||||
For a much more in-depth discussion of testing, see the :doc:`testing topic
 | 
			
		||||
guide </topics/testing>`.
 | 
			
		||||
@@ -1,137 +0,0 @@
 | 
			
		||||
===================
 | 
			
		||||
Customizing Horizon
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
Changing the Site Title
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
The OpenStack Dashboard Site Title branding (i.e. "**OpenStack** Dashboard")
 | 
			
		||||
can be overwritten by adding the attribute ``SITE_BRANDING``
 | 
			
		||||
to ``local_settings.py`` with the value being the desired name.
 | 
			
		||||
 | 
			
		||||
The file ``local_settings.py`` can be found at the Horizon directory path of
 | 
			
		||||
``horizon/openstack-dashboard/local/local_settings.py``.
 | 
			
		||||
 | 
			
		||||
Changing the Logo
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
The OpenStack Logo is pulled in through ``style.css``::
 | 
			
		||||
 | 
			
		||||
    #splash .modal {
 | 
			
		||||
        background: #fff url(../images/logo.png) no-repeat center 35px;
 | 
			
		||||
 | 
			
		||||
    h1.brand a {
 | 
			
		||||
        background: url(../images/logo.png) top left no-repeat;
 | 
			
		||||
 | 
			
		||||
To override the OpenStack Logo image, replace the image at the directory path
 | 
			
		||||
``horizon/openstack-dashboard/dashboard/static/dashboard/images/logo.png``.
 | 
			
		||||
 | 
			
		||||
The dimensions should be ``width: 108px, height: 121px``.
 | 
			
		||||
 | 
			
		||||
Modifying Existing Dashboards and Panels
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
If you wish to alter dashboards or panels which are not part of your codebase,
 | 
			
		||||
you can specify a custom python module which will be loaded after the entire
 | 
			
		||||
Horizon site has been initialized, but prior to the URLconf construction.
 | 
			
		||||
This allows for common site-customization requirements such as:
 | 
			
		||||
 | 
			
		||||
* Registering or unregistering panels from an existing dashboard.
 | 
			
		||||
* Changing the names of dashboards and panels.
 | 
			
		||||
* Re-ordering panels within a dashboard or panel group.
 | 
			
		||||
 | 
			
		||||
To specify the python module containing your modifications, add the key
 | 
			
		||||
``customization_module`` to your ``settings.HORIZON_CONFIG`` dictionary.
 | 
			
		||||
The value should be a string containing the path to your module in dotted
 | 
			
		||||
python path notation. Example::
 | 
			
		||||
 | 
			
		||||
    HORIZON_CONFIG = {
 | 
			
		||||
        "customization_module": "my_project.overrides"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
You can do essentially anything you like in the customization module. For
 | 
			
		||||
example, you could change the name of a panel::
 | 
			
		||||
 | 
			
		||||
    from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
    import horizon
 | 
			
		||||
 | 
			
		||||
    # Rename "User Settings" to "User Options"
 | 
			
		||||
    settings = horizon.get_dashboard("settings")
 | 
			
		||||
    user_panel = settings.get_panel("user")
 | 
			
		||||
    user_panel.name = _("User Options")
 | 
			
		||||
 | 
			
		||||
Or get the instances panel::
 | 
			
		||||
 | 
			
		||||
    projects_dashboard = horizon.get_dashboard("project")
 | 
			
		||||
    instances_panel = projects_dashboard.get_panel("instances")
 | 
			
		||||
 | 
			
		||||
And limit access to users with the Keystone Admin role::
 | 
			
		||||
 | 
			
		||||
    permissions = list(getattr(instances_panel, 'permissions', []))
 | 
			
		||||
    permissions.append('openstack.roles.admin')
 | 
			
		||||
    instances_panel.permissions = tuple(permissions)
 | 
			
		||||
 | 
			
		||||
Or just remove it entirely::
 | 
			
		||||
 | 
			
		||||
    projects_dashboard.unregister(instances_panel.__class__)
 | 
			
		||||
 | 
			
		||||
.. NOTE::
 | 
			
		||||
 | 
			
		||||
    ``my_project.overrides`` needs to be importable by the python process running
 | 
			
		||||
    Horizon.
 | 
			
		||||
    If your module is not installed as a system-wide python package,
 | 
			
		||||
    you can either make it installable (e.g., with a setup.py)
 | 
			
		||||
    or you can adjust the python path used by your WSGI server to include its location.
 | 
			
		||||
 | 
			
		||||
    Probably the easiest way is to add a ``python-path`` argument to
 | 
			
		||||
    the ``WSGIDaemonProcess`` line in Apache's Horizon config.
 | 
			
		||||
 | 
			
		||||
    Assuming your ``my_project`` module lives in ``/opt/python/my_project``,
 | 
			
		||||
    you'd make it look like the following::
 | 
			
		||||
 | 
			
		||||
        WSGIDaemonProcess [... existing options ...] python-path=/opt/python
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Button Icons
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
Horizon provides hooks for customizing the look and feel of each class of
 | 
			
		||||
button on the site. The following classes are used to identify each type of
 | 
			
		||||
button:
 | 
			
		||||
 | 
			
		||||
* Generic Classes
 | 
			
		||||
    * btn-search
 | 
			
		||||
    * btn-delete
 | 
			
		||||
    * btn-upload
 | 
			
		||||
    * btn-download
 | 
			
		||||
    * btn-create
 | 
			
		||||
    * btn-edit
 | 
			
		||||
    * btn-list
 | 
			
		||||
    * btn-copy
 | 
			
		||||
    * btn-camera
 | 
			
		||||
    * btn-stats
 | 
			
		||||
    * btn-enable
 | 
			
		||||
    * btn-disable
 | 
			
		||||
 | 
			
		||||
* Floating IP-specific Classes
 | 
			
		||||
    * btn-allocate
 | 
			
		||||
    * btn-release
 | 
			
		||||
    * btn-associate
 | 
			
		||||
    * btn-disassociate
 | 
			
		||||
 | 
			
		||||
* Instance-specific Classes
 | 
			
		||||
    * btn-launch
 | 
			
		||||
    * btn-terminate
 | 
			
		||||
    * btn-reboot
 | 
			
		||||
    * btn-pause
 | 
			
		||||
    * btn-suspend
 | 
			
		||||
    * btn-console
 | 
			
		||||
    * btn-log
 | 
			
		||||
 | 
			
		||||
* Volume-specific classes
 | 
			
		||||
    * btn-detach
 | 
			
		||||
 | 
			
		||||
Additionally, the site-wide default button classes can be configured by
 | 
			
		||||
setting ``ACTION_CSS_CLASSES`` to a tuple of the classes you wish to appear
 | 
			
		||||
on all action buttons in your ``local_settings.py`` file.
 | 
			
		||||
@@ -1,217 +0,0 @@
 | 
			
		||||
=================
 | 
			
		||||
Deploying Horizon
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
This guide aims to cover some common questions, concerns and pitfalls you
 | 
			
		||||
may encounter when deploying Horizon in a production environment.
 | 
			
		||||
 | 
			
		||||
.. seealso:: :doc:`settings`
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    The Service Catalog returned by the Identity Service after a user
 | 
			
		||||
    has successfully authenticated determines the dashboards and panels
 | 
			
		||||
    that will be available within the OpenStack Dashboard. If you are not
 | 
			
		||||
    seeing a particular service you expected (e.g. Object Storage/Swift or
 | 
			
		||||
    Networking/Neutron) make sure your Service Catalog is configured correctly.
 | 
			
		||||
 | 
			
		||||
    Prior to the Essex release of Horizon these features were controlled by
 | 
			
		||||
    individual settings in the ``local_settings.py`` file. This code has been
 | 
			
		||||
    long-since removed and those pre-Essex settings have no impact now.
 | 
			
		||||
 | 
			
		||||
Configure Your Identity Service Host
 | 
			
		||||
====================================
 | 
			
		||||
 | 
			
		||||
The one thing you *must* do in order to run Horizon is to specify the
 | 
			
		||||
host for your OpenStack Identity Service endpoint. To do this, set the value
 | 
			
		||||
of the ``OPENSTACK_HOST`` settings in your ``local_settings.py`` file.
 | 
			
		||||
 | 
			
		||||
Logging
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
Logging is an important concern for production deployments, and the intricacies
 | 
			
		||||
of good logging configuration go far beyond what can be covered here. However
 | 
			
		||||
there are a few points worth noting about the logging included with Horizon,
 | 
			
		||||
how to customize it, and where other components may take over:
 | 
			
		||||
 | 
			
		||||
* Horizon's logging uses Django's logging configuration mechanism, which
 | 
			
		||||
  can be customized in your ``local_settings.py`` file through the
 | 
			
		||||
  ``LOGGING`` dictionary.
 | 
			
		||||
* Horizon's default logging example sets the log level to ``"INFO"``, which is
 | 
			
		||||
  a reasonable choice for production deployments. For development, however,
 | 
			
		||||
  you may want to change the log level to ``"DEBUG"``.
 | 
			
		||||
* Horizon also uses a number of 3rd-party clients which log separately. The
 | 
			
		||||
  log level for these can still be controlled through Horizon's ``LOGGING``
 | 
			
		||||
  config, however behaviors may vary beyond Horizon's control.
 | 
			
		||||
* For more information regarding configuring logging in Horizon, please
 | 
			
		||||
  read the `Django logging directive`_ and the `Python logging directive`_
 | 
			
		||||
  documentation. Horizon is built on Python and Django.
 | 
			
		||||
 | 
			
		||||
.. _Django logging directive: https://docs.djangoproject.com/en/1.5/topics/logging
 | 
			
		||||
.. _Python logging directive: http://docs.python.org/2/library/logging.html
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
    At this time there is `a known bug in python-keystoneclient`_ where it will
 | 
			
		||||
    log the complete request body of any request sent to Keystone through it
 | 
			
		||||
    (including logging passwords in plain text) when the log level is set to
 | 
			
		||||
    ``"DEBUG"``. If this behavior is not desired, make sure your log level is
 | 
			
		||||
    ``"INFO"`` or higher.
 | 
			
		||||
 | 
			
		||||
.. _a known bug in python-keystoneclient: https://bugs.launchpad.net/keystone/+bug/1004114
 | 
			
		||||
 | 
			
		||||
File Uploads
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
Horizon allows users to upload files via their web browser to other OpenStack
 | 
			
		||||
services such as Glance and Swift. Files uploaded through this mechanism are
 | 
			
		||||
first stored on the Horizon server before being forwarded on - files are not
 | 
			
		||||
uploaded directly or streamed as Horizon receives them. As Horizon itself does
 | 
			
		||||
not impose any restrictions on the size of file uploads, production deployments
 | 
			
		||||
will want to consider configuring their server hosting the Horizon application
 | 
			
		||||
to enforce such a limit to prevent large uploads exhausting system resources
 | 
			
		||||
and disrupting services. Deployments using Apache2 can use the
 | 
			
		||||
`LimitRequestBody directive`_ to achieve this.
 | 
			
		||||
 | 
			
		||||
Uploads to the Glance image store service tend to be particularly large - in
 | 
			
		||||
the order of hundreds of megabytes to multiple gigabytes. Deployments are able
 | 
			
		||||
to disable the ability to upload images through Horizon by setting
 | 
			
		||||
``HORIZON_IMAGES_ALLOW_UPLOAD`` to ``False`` in your ``local_settings.py``
 | 
			
		||||
file.
 | 
			
		||||
 | 
			
		||||
 .. _LimitRequestBody directive: http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestbody
 | 
			
		||||
 | 
			
		||||
Session Storage
 | 
			
		||||
===============
 | 
			
		||||
 | 
			
		||||
Horizon uses `Django's sessions framework`_ for handling user session data;
 | 
			
		||||
however that's not the end of the story. There are numerous session backends
 | 
			
		||||
available, which are controlled through the ``SESSION_ENGINE`` setting in
 | 
			
		||||
your ``local_settings.py`` file. What follows is a quick discussion of the
 | 
			
		||||
pros and cons of each of the common options as they pertain to deploying
 | 
			
		||||
Horizon specifically.
 | 
			
		||||
 | 
			
		||||
.. _Django's sessions framework: https://docs.djangoproject.com/en/dev/topics/http/sessions/
 | 
			
		||||
 | 
			
		||||
Local Memory Cache
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
Enabled by::
 | 
			
		||||
 | 
			
		||||
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
 | 
			
		||||
    CACHES = {
 | 
			
		||||
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Local memory storage is the quickest and easiest session backend to set up,
 | 
			
		||||
as it has no external dependencies whatsoever. However, it has two significant
 | 
			
		||||
drawbacks:
 | 
			
		||||
 | 
			
		||||
  * No shared storage across processes or workers.
 | 
			
		||||
  * No persistence after a process terminates.
 | 
			
		||||
 | 
			
		||||
The local memory backend is enabled as the default for Horizon solely because
 | 
			
		||||
it has no dependencies. It is not recommended for production use, or even for
 | 
			
		||||
serious development work. For better options, read on.
 | 
			
		||||
 | 
			
		||||
Memcached
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
Enabled by::
 | 
			
		||||
 | 
			
		||||
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
 | 
			
		||||
    CACHES = {
 | 
			
		||||
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache'
 | 
			
		||||
        'LOCATION': 'my_memcached_host:11211',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
External caching using an application such as memcached offers persistence
 | 
			
		||||
and shared storage, and can be very useful for small-scale deployment and/or
 | 
			
		||||
development. However, for distributed and high-availability scenarios
 | 
			
		||||
memcached has inherent problems which are beyond the scope of this
 | 
			
		||||
documentation.
 | 
			
		||||
 | 
			
		||||
Memcached is an extremely fast and efficient cache backend for cases where it
 | 
			
		||||
fits the deployment need. But it's not appropriate for all scenarios.
 | 
			
		||||
 | 
			
		||||
Requirements:
 | 
			
		||||
 | 
			
		||||
  * Memcached service running and accessible.
 | 
			
		||||
  * Python memcached module installed.
 | 
			
		||||
 | 
			
		||||
Database
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
Enabled by::
 | 
			
		||||
 | 
			
		||||
    SESSION_ENGINE = 'django.core.cache.backends.db.DatabaseCache'
 | 
			
		||||
    DATABASES = {
 | 
			
		||||
        'default': {
 | 
			
		||||
            # Databe configuration here
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Database-backed sessions are scalable (using an appropriate database strategy),
 | 
			
		||||
persistent, and can be made high-concurrency and highly-available.
 | 
			
		||||
 | 
			
		||||
The downside to this approach is that database-backed sessions are one of the
 | 
			
		||||
slower session storages, and incur a high overhead under heavy usage. Proper
 | 
			
		||||
configuration of your database deployment can also be a substantial
 | 
			
		||||
undertaking and is far beyond the scope of this documentation.
 | 
			
		||||
 | 
			
		||||
Cached Database
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
To mitigate the performance issues of database queries, you can also consider
 | 
			
		||||
using Django's ``cached_db`` session backend which utilizes both your database
 | 
			
		||||
and caching infrastructure to perform write-through caching and efficient
 | 
			
		||||
retrieval. You can enable this hybrid setting by configuring both your database
 | 
			
		||||
and cache as discussed above and then using::
 | 
			
		||||
 | 
			
		||||
    SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
 | 
			
		||||
 | 
			
		||||
Cookies
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
If you're using Django 1.4 or later, a new session backend is available to you
 | 
			
		||||
which avoids server load and scaling problems: the ``signed_cookies`` backend!
 | 
			
		||||
 | 
			
		||||
This backend stores session data in a cookie which is stored by the
 | 
			
		||||
user's browser. The backend uses a cryptographic signing technique to ensure
 | 
			
		||||
session data is not tampered with during transport (**this is not the same
 | 
			
		||||
as encryption, session data is still readable by an attacker**).
 | 
			
		||||
 | 
			
		||||
The pros of this session engine are that it doesn't require any additional
 | 
			
		||||
dependencies or infrastructure overhead, and it scales indefinitely as long
 | 
			
		||||
as the quantity of session data being stored fits into a normal cookie.
 | 
			
		||||
 | 
			
		||||
The biggest downside is that it places session data into storage on the user's
 | 
			
		||||
machine and transports it over the wire. It also limits the quantity of
 | 
			
		||||
session data which can be stored.
 | 
			
		||||
 | 
			
		||||
For a thorough discussion of the security implications of this session backend,
 | 
			
		||||
please read the `Django documentation on cookie-based sessions`_.
 | 
			
		||||
 | 
			
		||||
.. _Django documentation on cookie-based sessions: https://docs.djangoproject.com/en/dev/topics/http/sessions/#using-cookie-based-sessions
 | 
			
		||||
 | 
			
		||||
Secure Site Recommendations
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
When implementing Horizon for public usage, with the website served through
 | 
			
		||||
HTTPS, it is recommended that the following settings are applied.
 | 
			
		||||
 | 
			
		||||
To help protect the session cookies from `cross-site scripting`_, add the
 | 
			
		||||
following to ``local_settings.py`` :
 | 
			
		||||
 | 
			
		||||
    CSRF_COOKIE_SECURE = True
 | 
			
		||||
    SESSION_COOKIE_SECURE = True
 | 
			
		||||
    SESSION_COOKIE_HTTPONLY = True
 | 
			
		||||
 | 
			
		||||
Note that the CSRF_COOKIE_SECURE option is only available from Django 1.4. It
 | 
			
		||||
does no harm to have the setting in earlier versions, but it does not take effect.
 | 
			
		||||
 | 
			
		||||
You can also disable `browser autocompletion`_ for the authentication form by
 | 
			
		||||
changing the ``password_autocomplete`` attribute to ``off`` in ``horizon/conf/default.py``
 | 
			
		||||
 | 
			
		||||
.. _cross-site scripting: https://www.owasp.org/index.php/HttpOnly
 | 
			
		||||
.. _browser autocompletion: https://wiki.mozilla.org/The_autocomplete_attribute_and_web_documents_using_XHTML
 | 
			
		||||
@@ -1,294 +0,0 @@
 | 
			
		||||
==================================
 | 
			
		||||
Horizon Settings and Configuration
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
Introduction
 | 
			
		||||
============
 | 
			
		||||
 | 
			
		||||
Horizon's settings tend to fall into three categories:
 | 
			
		||||
 | 
			
		||||
* Horizon configuration options (contained in the ``HORIZON_CONFIG`` dict)
 | 
			
		||||
  which are not OpenStack-specific and pertain only to the core framework.
 | 
			
		||||
* OpenStack-related settings which pertain to other projects/services and
 | 
			
		||||
  are generally prefixed with ``OPENSTACK_`` in the settings file.
 | 
			
		||||
* Django settings (including common plugins like ``django-compressor``) which
 | 
			
		||||
  can be (and should be) read about in their respective documentation.
 | 
			
		||||
 | 
			
		||||
What follows is an overview of the Horizon and OpenStack-specific settings
 | 
			
		||||
and a few notes on the Django-related settings.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    Prior to the Essex release of Horizon there were settings which controlled
 | 
			
		||||
    whether features such as Object Storage/Swift or Networking/Neutron would be
 | 
			
		||||
    enabled in the OpenStack Dashboard. This code has beenlong-since removed and
 | 
			
		||||
    those pre-Essex settings have no impact now.
 | 
			
		||||
 | 
			
		||||
    In Essex and later, the Service Catalog returned by the Identity Service
 | 
			
		||||
    after a user has successfully authenticated determines the dashboards and
 | 
			
		||||
    panels that will be available within the OpenStack Dashboard. If you are not
 | 
			
		||||
    seeing a particular service you expected make sure your Service Catalog is
 | 
			
		||||
    configured correctly.
 | 
			
		||||
 | 
			
		||||
Horizon Settings
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
The following options are available in order to configure/customize the
 | 
			
		||||
behavior of your Horizon installation. All of them are contained in the
 | 
			
		||||
``HORIZON_CONFIG`` dictionary.
 | 
			
		||||
 | 
			
		||||
``dashboards``
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
Default: ``None``
 | 
			
		||||
 | 
			
		||||
A list containing the slugs of any dashboards which should be active in this
 | 
			
		||||
Horizon installation. The dashboards listed must be in a Python module which
 | 
			
		||||
is included in the ``INSTALLED_APPS`` list and on the Python path.
 | 
			
		||||
 | 
			
		||||
``default_dashboard``
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
Default: ``None``
 | 
			
		||||
 | 
			
		||||
The slug of the dashboard which should act as the first-run/fallback dashboard
 | 
			
		||||
whenever a user logs in or is otherwise redirected to an ambiguous location.
 | 
			
		||||
 | 
			
		||||
``user_home``
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Default: ``settings.LOGIN_REDIRECT_URL``
 | 
			
		||||
 | 
			
		||||
This can be either a literal URL path (such as the default), or Python's
 | 
			
		||||
dotted string notation representing a function which will evaluate what URL
 | 
			
		||||
a user should be redirected to based on the attributes of that user.
 | 
			
		||||
 | 
			
		||||
``ajax_queue_limit``
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
Default: ``10``
 | 
			
		||||
 | 
			
		||||
The maximum number of simultaneous AJAX connections the dashboard may try
 | 
			
		||||
to make. This is particularly relevant when monitoring a large number of
 | 
			
		||||
instances, volumes, etc. which are all actively trying to update/change state.
 | 
			
		||||
 | 
			
		||||
``ajax_poll_interval``
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
Default: ``2500``
 | 
			
		||||
 | 
			
		||||
How frequently resources in transition states should be polled for updates,
 | 
			
		||||
expressed in milliseconds.
 | 
			
		||||
 | 
			
		||||
``help_url``
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Default: None
 | 
			
		||||
 | 
			
		||||
If provided, a "Help" link will be displayed in the site header which links
 | 
			
		||||
to the value of this settings (ideally a URL containing help information).
 | 
			
		||||
 | 
			
		||||
``exceptions``
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
Default: ``{'unauthorized': [], 'not_found': [], 'recoverable': []}``
 | 
			
		||||
 | 
			
		||||
A dictionary containing classes of exceptions which Horizon's centralized
 | 
			
		||||
exception handling should be aware of.
 | 
			
		||||
 | 
			
		||||
``password_validator``
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
Default: {'regex': '.*', 'help_text': _("Password is not accepted")}
 | 
			
		||||
 | 
			
		||||
A dictionary containing a regular expression which will be used for password
 | 
			
		||||
validation and help text which will be displayed if the password does not
 | 
			
		||||
pass validation. The help text should describe the password requirements if
 | 
			
		||||
there are any.
 | 
			
		||||
 | 
			
		||||
This setting allows you to set rules for passwords if your organization
 | 
			
		||||
requires them.
 | 
			
		||||
 | 
			
		||||
``password_autocomplete``
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``"on"``
 | 
			
		||||
 | 
			
		||||
Controls whether browser autocompletion should be enabled on the login form.
 | 
			
		||||
Valid values are ``"on"`` and ``"off"``.
 | 
			
		||||
 | 
			
		||||
``simple_ip_management``
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``True``
 | 
			
		||||
 | 
			
		||||
Enable or disable simplified floating IP address management.
 | 
			
		||||
 | 
			
		||||
"Simple" floating IP address management means that the user does not ever have
 | 
			
		||||
to select the specific IP addresses they wish to use, and the process of
 | 
			
		||||
allocating an IP and assigning it to an instance is one-click.
 | 
			
		||||
 | 
			
		||||
The "advanced" floating IP management allows users to select the floating IP
 | 
			
		||||
pool from which the IP should be allocated and to select a specific IP address
 | 
			
		||||
when associating one with an instance.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
OpenStack Settings
 | 
			
		||||
==================
 | 
			
		||||
 | 
			
		||||
The following settings inform the OpenStack Dashboard of information about the
 | 
			
		||||
other OpenStack projects which are part of this cloud and control the behavior
 | 
			
		||||
of specific dashboards, panels, API calls, etc.
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_HOST``
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
Default: ``"127.0.0.1"``
 | 
			
		||||
 | 
			
		||||
The hostname of the Keystone server used for authentication if you only have
 | 
			
		||||
one region. This is often the *only* settings that needs to be set for a
 | 
			
		||||
basic deployment.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_KEYSTONE_URL``
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``"http://%s:5000/v2.0" % OPENSTACK_HOST``
 | 
			
		||||
 | 
			
		||||
The full URL for the Keystone endpoint used for authentication. Unless you
 | 
			
		||||
are using HTTPS, running your Keystone server on a nonstandard port, or using
 | 
			
		||||
a nonstandard URL scheme you shouldn't need to touch this setting.
 | 
			
		||||
 | 
			
		||||
``AVAILABLE_REGIONS``
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
Default: ``None``
 | 
			
		||||
 | 
			
		||||
A tuple of tuples which define multiple regions. The tuple format is
 | 
			
		||||
``('http://{{keystone_host}}:5000/v2.0', '{{region_name}}')``. If any regions
 | 
			
		||||
are specified the login form will have a dropdown selector for authenticating
 | 
			
		||||
to the appropriate region, and there will be a region switcher dropdown in
 | 
			
		||||
the site header when logged in.
 | 
			
		||||
 | 
			
		||||
If you do not have multiple regions you should use the ``OPENSTACK_HOST`` and
 | 
			
		||||
``OPENSTACK_KEYSTONE_URL`` settings above instead.
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_KEYSTONE_DEFAULT_ROLE``
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
Default: "Member"
 | 
			
		||||
 | 
			
		||||
The name of the role which will be assigned to a user when added to a project.
 | 
			
		||||
This name must correspond to a role name in Keystone.
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_SSL_NO_VERIFY``
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``False``
 | 
			
		||||
 | 
			
		||||
Disable SSL certificate checks in the OpenStack clients (useful for self-signed
 | 
			
		||||
certificates).
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_KEYSTONE_BACKEND``
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``{'name': 'native', 'can_edit_user': True, 'can_edit_project': True}``
 | 
			
		||||
 | 
			
		||||
A dictionary containing settings which can be used to identify the
 | 
			
		||||
capabilities of the auth backend for Keystone.
 | 
			
		||||
 | 
			
		||||
If Keystone has been configured to use LDAP as the auth backend then set
 | 
			
		||||
``can_edit_user`` and ``can_edit_project`` to ``False`` and name to ``"ldap"``.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_HYPERVISOR_FEATURES``
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``{'can_set_mount_point': True, 'can_encrypt_volumes': False}``
 | 
			
		||||
 | 
			
		||||
A dictionary containing settings which can be used to identify the
 | 
			
		||||
capabilities of the hypervisor for Nova.
 | 
			
		||||
 | 
			
		||||
Some hypervisors have the ability to set the mount point for volumes attached
 | 
			
		||||
to instances (KVM does not). Setting ``can_set_mount_point`` to ``False`` will
 | 
			
		||||
remove the option to set the mount point from the UI.
 | 
			
		||||
 | 
			
		||||
In the Havana release, there will be a feature for encrypted volumes
 | 
			
		||||
which will be controlled by the ``can_encrypt_volumes``. Setting it to ``True``
 | 
			
		||||
in the Grizzly release will have no effect.
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_NEUTRON_NETWORK``
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``{'enable_lb': False}``
 | 
			
		||||
 | 
			
		||||
A dictionary of settings which can be used to enable optional services provided
 | 
			
		||||
by neutron.  Currently only the load balancer service is available.
 | 
			
		||||
 | 
			
		||||
``OPENSTACK_ENDPOINT_TYPE``
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``"internalURL"``
 | 
			
		||||
 | 
			
		||||
A string which specifies the endpoint type to use for the endpoints in the
 | 
			
		||||
Keystone service catalog. If Horizon is running external to the OpenStack
 | 
			
		||||
environment you may wish to use ``"publicURL"`` instead.
 | 
			
		||||
 | 
			
		||||
``API_RESULT_LIMIT``
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
Default: ``1000``
 | 
			
		||||
 | 
			
		||||
The maximum number of objects (e.g. Swift objects or Glance images) to display
 | 
			
		||||
on a single page before providing a paging element (a "more" link) to paginate
 | 
			
		||||
results.
 | 
			
		||||
 | 
			
		||||
``API_RESULT_PAGE_SIZE``
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``20``
 | 
			
		||||
 | 
			
		||||
Similar to ``API_RESULT_LIMIT``. This setting currently only controls the
 | 
			
		||||
Glance image list page size. It will be removed in a future version.
 | 
			
		||||
 | 
			
		||||
Django Settings (Partial)
 | 
			
		||||
=========================
 | 
			
		||||
 | 
			
		||||
.. warning::
 | 
			
		||||
 | 
			
		||||
    This is not meant to be anywhere near a complete list of settings for
 | 
			
		||||
    Django. You should always consult the upstream documentation, especially
 | 
			
		||||
    with regards to deployment considerations and security best-practices.
 | 
			
		||||
 | 
			
		||||
There are a few key settings you should be aware of for development and the
 | 
			
		||||
most basic of deployments. Further recommendations can be found in the
 | 
			
		||||
Deploying Horizon section of this documentation.
 | 
			
		||||
 | 
			
		||||
``DEBUG`` and ``TEMPLATE_DEBUG``
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
Default: ``True``
 | 
			
		||||
 | 
			
		||||
Controls whether unhandled exceptions should generate a generic 500 response
 | 
			
		||||
or present the user with a pretty-formatted debug information page.
 | 
			
		||||
 | 
			
		||||
This setting should **always** be set to ``False`` for production deployments
 | 
			
		||||
as the debug page can display sensitive information to users and attackers
 | 
			
		||||
alike.
 | 
			
		||||
 | 
			
		||||
``SECRET_KEY``
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
This should absolutely be set to a unique (and secret) value for your
 | 
			
		||||
deployment. Unless you are running a load-balancer with multiple Horizon
 | 
			
		||||
installations behind it, each Horizon instance should have a unique secret key.
 | 
			
		||||
 | 
			
		||||
The ``local_settings.py.example`` file includes a quick-and-easy way to
 | 
			
		||||
generate a secret key for a single installation.
 | 
			
		||||
 | 
			
		||||
``SECURE_PROXY_SSL_HEADER``, ``CSRF_COOKIE_SECURE`` and ``SESSION_COOKIE_SECURE``
 | 
			
		||||
---------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
These three settings should be configured if you are deploying Horizon with
 | 
			
		||||
SSL. The values indicated in the default ``local_settings.py.example`` file
 | 
			
		||||
are generally safe to use.
 | 
			
		||||
@@ -1,129 +0,0 @@
 | 
			
		||||
======================
 | 
			
		||||
DataTables Topic Guide
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
Horizon provides the :mod:`horizon.tables` module to provide
 | 
			
		||||
a convenient, reusable API for building data-driven displays and interfaces.
 | 
			
		||||
The core components of this API fall into three categories: ``DataTables``,
 | 
			
		||||
``Actions``, and ``Class-based Views``.
 | 
			
		||||
 | 
			
		||||
  .. seealso::
 | 
			
		||||
 | 
			
		||||
    For a detailed API information check out the :doc:`DataTables Reference
 | 
			
		||||
    Guide </ref/tables>`.
 | 
			
		||||
 | 
			
		||||
Tables
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
The majority of interface in a dashboard-style interface ends up being
 | 
			
		||||
tabular displays of the various resources the dashboard interacts with.
 | 
			
		||||
The :class:`~horizon.tables.DataTable` class exists so you don't have to
 | 
			
		||||
reinvent the wheel each time.
 | 
			
		||||
 | 
			
		||||
Creating your own tables
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
Creating a table is fairly simple:
 | 
			
		||||
 | 
			
		||||
  #. Create a subclass of :class:`~horizon.tables.DataTable`.
 | 
			
		||||
  #. Define columns on it using :class:`~horizon.tables.Column`.
 | 
			
		||||
  #. Create an inner ``Meta`` class to contain the special options for
 | 
			
		||||
     this table.
 | 
			
		||||
  #. Define any actions for the table, and add them to
 | 
			
		||||
     :attr:`~horizon.tables.DataTableOptions.table_actions` or
 | 
			
		||||
     :attr:`~horizon.tables.DataTableOptions.row_actions`.
 | 
			
		||||
 | 
			
		||||
Examples of this can be found in any of the ``tables.py`` modules included
 | 
			
		||||
in the reference modules under ``horizon.dashboards``.
 | 
			
		||||
 | 
			
		||||
Connecting a table to a view
 | 
			
		||||
----------------------------
 | 
			
		||||
 | 
			
		||||
Once you've got your table set up the way you like it, the next step is to
 | 
			
		||||
wire it up to a view. To make this as easy as possible Horizon provides the
 | 
			
		||||
:class:`~horizon.tables.DataTableView` class-based view which can be subclassed
 | 
			
		||||
to display your table with just a couple lines of code. At it's simplest it
 | 
			
		||||
looks like this::
 | 
			
		||||
 | 
			
		||||
    from horizon import tables
 | 
			
		||||
    from .tables import MyTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class MyTableView(tables.DataTableView):
 | 
			
		||||
        table_class = MyTable
 | 
			
		||||
        template_name = "my_app/my_table_view.html"
 | 
			
		||||
 | 
			
		||||
        def get_data(self):
 | 
			
		||||
            return my_api.objects.list()
 | 
			
		||||
 | 
			
		||||
In the template you would just need to include the following to render the
 | 
			
		||||
table::
 | 
			
		||||
 | 
			
		||||
    {{ table.render }}
 | 
			
		||||
 | 
			
		||||
That's it! Easy, right?
 | 
			
		||||
 | 
			
		||||
Actions
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
Actions comprise any manipulations that might happen on the data in the table
 | 
			
		||||
or the table itself. For example, this may be the standard object CRUD, linking
 | 
			
		||||
to related views based on the object's id, filtering the data in the table,
 | 
			
		||||
or fetching updated data when appropriate.
 | 
			
		||||
 | 
			
		||||
When actions get run
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
There are two points in the request-response cycle in which actions can
 | 
			
		||||
take place; prior to data being loaded into the table, and after the data
 | 
			
		||||
is loaded. When you're using one of the pre-built class-based views for
 | 
			
		||||
working with your tables the pseudo-workflow looks like this:
 | 
			
		||||
 | 
			
		||||
  #. The request enters view.
 | 
			
		||||
  #. The table class is instantiated without data.
 | 
			
		||||
  #. Any "preemptive" actions are checked to see if they should run.
 | 
			
		||||
  #. Data is fetched and loaded into the table.
 | 
			
		||||
  #. All other actions are checked to see if they should run.
 | 
			
		||||
  #. If none of the actions have caused an early exit from the view,
 | 
			
		||||
     the standard response from the view is returned (usually the
 | 
			
		||||
     rendered table).
 | 
			
		||||
 | 
			
		||||
The benefit of the multi-step table instantiation is that you can use
 | 
			
		||||
preemptive actions which don't need access to the entire collection of data
 | 
			
		||||
to save yourself on processing overhead, API calls, etc.
 | 
			
		||||
 | 
			
		||||
Basic actions
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
At their simplest, there are three types of actions: actions which act on the
 | 
			
		||||
data in the table, actions which link to related resources, and actions that
 | 
			
		||||
alter which data is displayed. These correspond to
 | 
			
		||||
:class:`~horizon.tables.Action`, :class:`~horizon.tables.LinkAction`, and
 | 
			
		||||
:class:`~horizon.tables.FilterAction`.
 | 
			
		||||
 | 
			
		||||
Writing your own actions generally starts with subclassing one of those
 | 
			
		||||
action classes and customizing the designated attributes and methods.
 | 
			
		||||
 | 
			
		||||
Shortcut actions
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
There are several common tasks for which Horizon provides pre-built shortcut
 | 
			
		||||
classes. These include :class:`~horizon.tables.BatchAction`, and
 | 
			
		||||
:class:`~horizon.tables.DeleteAction`. Each of these abstracts away nearly
 | 
			
		||||
all of the boilerplate associated with writing these types of actions and
 | 
			
		||||
provides consistent error handling, logging, and user-facing interaction.
 | 
			
		||||
 | 
			
		||||
It is worth noting that ``BatchAction`` and ``DeleteAction`` are extensions
 | 
			
		||||
of the standard ``Action`` class.
 | 
			
		||||
 | 
			
		||||
Preemptive actions
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
Action classes which have their :attr:`~horizon.tables.Action.preempt`
 | 
			
		||||
attribute set to ``True`` will be evaluated before any data is loaded into
 | 
			
		||||
the table. As such, you must be careful not to rely on any table methods that
 | 
			
		||||
require data, such as :meth:`~horizon.tables.DataTable.get_object_display` or
 | 
			
		||||
:meth:`~horizon.tables.DataTable.get_object_by_id`. The advantage of preemptive
 | 
			
		||||
actions is that you can avoid having to do all the processing, API calls, etc.
 | 
			
		||||
associated with loading data into the table for actions which don't require
 | 
			
		||||
access to that information.
 | 
			
		||||
@@ -1,276 +0,0 @@
 | 
			
		||||
===================
 | 
			
		||||
Testing Topic Guide
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
Having good tests in place is absolutely critical for ensuring a stable,
 | 
			
		||||
maintainable codebase. Hopefully that doesn't need any more explanation.
 | 
			
		||||
 | 
			
		||||
However, what defines a "good" test is not always obvious, and there are
 | 
			
		||||
a lot of common pitfalls that can easily shoot your test suite in the
 | 
			
		||||
foot.
 | 
			
		||||
 | 
			
		||||
If you already know everything about testing but are fed up with trying to
 | 
			
		||||
debug why a specific test failed, you can skip the intro and jump
 | 
			
		||||
stright to :ref:`debugging_unit_tests`.
 | 
			
		||||
 | 
			
		||||
An overview of testing
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
There are three main types of tests, each with their associated pros and cons:
 | 
			
		||||
 | 
			
		||||
Unit tests
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
These are isolated, stand-alone tests with no external dependencies. They are
 | 
			
		||||
written from the a perspective of "knowing the code", and test the assumptions
 | 
			
		||||
of the codebase and the developer.
 | 
			
		||||
 | 
			
		||||
Pros:
 | 
			
		||||
 | 
			
		||||
* Generally lightweight and fast.
 | 
			
		||||
* Can be run anywhere, anytime since they have no external dependencies.
 | 
			
		||||
 | 
			
		||||
Cons:
 | 
			
		||||
 | 
			
		||||
* Easy to be lax in writing them, or lazy in constructing them.
 | 
			
		||||
* Can't test interactions with live external services.
 | 
			
		||||
 | 
			
		||||
Functional tests
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
These are generally also isolated tests, though sometimes they may interact
 | 
			
		||||
with other services running locally. The key difference between functional
 | 
			
		||||
tests and unit tests, however, is that functional tests are written from the
 | 
			
		||||
perspective of the user (who knows nothing about the code) and only knows
 | 
			
		||||
what they put in and what they get back. Essentially this is a higher-level
 | 
			
		||||
testing of "does the result match the spec?".
 | 
			
		||||
 | 
			
		||||
Pros:
 | 
			
		||||
 | 
			
		||||
* Ensures that your code *always* meets the stated functional requirements.
 | 
			
		||||
* Verifies things from an "end user" perspective, which helps to ensure
 | 
			
		||||
  a high-quality experience.
 | 
			
		||||
* Designing your code with a functional testing perspective in mind helps
 | 
			
		||||
  keep a higher-level viewpoint in mind.
 | 
			
		||||
 | 
			
		||||
Cons:
 | 
			
		||||
 | 
			
		||||
* Requires an additional layer of thinking to define functional requirements
 | 
			
		||||
  in terms of inputs and outputs.
 | 
			
		||||
* Often requires writing a separate set of tests and/or using a different
 | 
			
		||||
  testing framework from your unit tests.
 | 
			
		||||
* Don't offer any insight into the quality or status of the underlying code,
 | 
			
		||||
  only verifies that it works or it doesn't.
 | 
			
		||||
 | 
			
		||||
Integration Tests
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
This layer of testing involves testing all of the components that your
 | 
			
		||||
codebase interacts with or relies on in conjunction. This is equivalent to
 | 
			
		||||
"live" testing, but in a repeatable manner.
 | 
			
		||||
 | 
			
		||||
Pros:
 | 
			
		||||
 | 
			
		||||
* Catches *many* bugs that unit and functional tests will not.
 | 
			
		||||
* Doesn't rely on assumptions about the inputs and outputs.
 | 
			
		||||
* Will warn you when changes in external components break your code.
 | 
			
		||||
 | 
			
		||||
Cons:
 | 
			
		||||
 | 
			
		||||
* Difficult and time-consuming to create a repeatable test environment.
 | 
			
		||||
* Did I mention that setting it up is a pain?
 | 
			
		||||
 | 
			
		||||
So what should I write?
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
A few simple guidelines:
 | 
			
		||||
 | 
			
		||||
#. Every bug fix should have a regression test. Period.
 | 
			
		||||
 | 
			
		||||
#. When writing a new feature, think about writing unit tests to verify
 | 
			
		||||
   the behavior step-by-step as you write the feature. Every time you'd
 | 
			
		||||
   go to run your code by hand and verify it manually, think "could I
 | 
			
		||||
   write a test to do this instead?". That way when the feature is done
 | 
			
		||||
   and you're ready to commit it you've already got a whole set of tests
 | 
			
		||||
   that are more thorough than anything you'd write after the fact.
 | 
			
		||||
 | 
			
		||||
#. Write tests that hit every view in your application. Even if they
 | 
			
		||||
   don't assert a single thing about the code, it tells you that your
 | 
			
		||||
   users aren't getting fatal errors just by interacting with your code.
 | 
			
		||||
 | 
			
		||||
What makes a good unit test?
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
Limiting our focus just to unit tests, there are a number of things you can
 | 
			
		||||
do to make your unit tests as useful, maintainable, and unburdensome as
 | 
			
		||||
possible.
 | 
			
		||||
 | 
			
		||||
Test data
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
Use a single, consistent set of test data. Grow it over time, but do everything
 | 
			
		||||
you can not to fragment it. It quickly becomes unmaintainable and perniciously
 | 
			
		||||
out-of-sync with reality.
 | 
			
		||||
 | 
			
		||||
Make your test data as accurate to reality as possible. Supply *all* the
 | 
			
		||||
attributes of an object, provide objects in all the various states you may want
 | 
			
		||||
to test.
 | 
			
		||||
 | 
			
		||||
If you do the first suggestion above *first* it makes the second one far less
 | 
			
		||||
painful. Write once, use everywhere.
 | 
			
		||||
 | 
			
		||||
To make your life even easier, if your codebase doesn't have a built-in
 | 
			
		||||
ORM-like function to manage your test data you can consider buidling (or
 | 
			
		||||
borrowing) one yourself. Being able to do simple retrieval queries on your
 | 
			
		||||
test data is incredibly valuable.
 | 
			
		||||
 | 
			
		||||
Mocking
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
Mocking is the practice of providing stand-ins for objects or pieces of code
 | 
			
		||||
you don't need to test. While convenient, they should be used with *extreme*
 | 
			
		||||
caution.
 | 
			
		||||
 | 
			
		||||
Why? Because overuse of mocks can rapidly land you in a situation where you're
 | 
			
		||||
not testing any real code. All you've done is verified that your mocking
 | 
			
		||||
framework returns what you tell it to. This problem can be very tricky to
 | 
			
		||||
recognize, since you may be mocking things in ``setUp`` methods, other modules,
 | 
			
		||||
etc.
 | 
			
		||||
 | 
			
		||||
A good rule of thumb is to mock as close to the source as possible. If you have
 | 
			
		||||
a function call that calls an external API in a view , mock out the external
 | 
			
		||||
API, not the whole function. If you mock the whole function you've suddenly
 | 
			
		||||
lost test coverage for an entire chunk of code *inside* your codebase. Cut the
 | 
			
		||||
ties cleanly right where your system ends and the external world begins.
 | 
			
		||||
 | 
			
		||||
Similarly, don't mock return values when you could construct a real return
 | 
			
		||||
value of the correct type with the correct attributes. You're just adding
 | 
			
		||||
another point of potential failure by exercising your mocking framework instead
 | 
			
		||||
of real code. Following the suggestions for testing above will make this a lot
 | 
			
		||||
less burdensome.
 | 
			
		||||
 | 
			
		||||
Assertions and verification
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
Think long and hard about what you really want to verify in your unit test. In
 | 
			
		||||
particular, think about what custom logic your code executes.
 | 
			
		||||
 | 
			
		||||
A common pitfall is to take a known test object, pass it through your code,
 | 
			
		||||
and then verify the properties of that object on the output. This is all well
 | 
			
		||||
and good, except if you're verifying properties that were untouched by your
 | 
			
		||||
code. What you want to check are the pieces that were *changed*, *added*, or
 | 
			
		||||
*removed*. Don't check the object's id attribute unless you have reason to
 | 
			
		||||
suspect it's not the object you started with. But if you added a new attribute
 | 
			
		||||
to it, be damn sure you verify that came out right.
 | 
			
		||||
 | 
			
		||||
It's also very common to avoid testing things you really care about because
 | 
			
		||||
it's more difficult. Verifying that the proper messages were displayed to the
 | 
			
		||||
user after an action, testing for form errors, making sure exception handling
 | 
			
		||||
is tested... these types of things aren't always easy, but they're extremely
 | 
			
		||||
necessary.
 | 
			
		||||
 | 
			
		||||
To that end, Horizon includes several custom assertions to make these tasks
 | 
			
		||||
easier. :meth:`~horizon.test.helpers.TestCase.assertNoFormErrors`,
 | 
			
		||||
:meth:`~horizon.test.helpers.TestCase.assertMessageCount`, and
 | 
			
		||||
:meth:`~horizon.test.helpers.TestCase.asertNoMessages` all exist for exactly
 | 
			
		||||
these purposes. Moreover, they provide useful output when things go wrong so
 | 
			
		||||
you're not left scratching your head wondering why your view test didn't
 | 
			
		||||
redirect as expected when you posted a form.
 | 
			
		||||
 | 
			
		||||
.. _debugging_unit_tests:
 | 
			
		||||
 | 
			
		||||
Debugging Unit Tests
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
Tips and tricks
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
#. Use :meth:`~horizon.test.helpers.TestCase.assertNoFormErrors` immediately
 | 
			
		||||
   after your ``client.post`` call for tests that handle form views. This will
 | 
			
		||||
   immediately fail if your form POST failed due to a validation error and
 | 
			
		||||
   tell you what the error was.
 | 
			
		||||
 | 
			
		||||
#. Use :meth:`~horizon.test.helpers.TestCase.assertMessageCount` and
 | 
			
		||||
   :meth:`~horizon.test.helpers.TestCase.asertNoMessages` when a piece of code
 | 
			
		||||
   is failing inexplicably. Since the core error handlers attach user-facing
 | 
			
		||||
   error messages (and since the core logging is silenced during test runs)
 | 
			
		||||
   these methods give you the dual benefit of verifying the output you expect
 | 
			
		||||
   while clearly showing you the problematic error message if they fail.
 | 
			
		||||
 | 
			
		||||
#. Use Python's ``pdb`` module liberally. Many people don't realize it works
 | 
			
		||||
   just as well in a test case as it does in a live view. Simply inserting
 | 
			
		||||
   ``import pdb; pdb.set_trace()`` anywhere in your codebase will drop the
 | 
			
		||||
   interpreter into an interactive shell so you can explore your test
 | 
			
		||||
   environment and see which of your assumptions about the code isn't,
 | 
			
		||||
   in fact, flawlessly correct.
 | 
			
		||||
 | 
			
		||||
Common pitfalls
 | 
			
		||||
---------------
 | 
			
		||||
 | 
			
		||||
There are a number of typical (and non-obvious) ways to break the unit tests.
 | 
			
		||||
Some common things to look for:
 | 
			
		||||
 | 
			
		||||
#. Make sure you stub out the method exactly as it's called in the code
 | 
			
		||||
   being tested. For example, if your real code calls
 | 
			
		||||
   ``api.keystone.tenant_get``, stubbing out ``api.tenant_get`` (available
 | 
			
		||||
   for legacy reasons) will fail.
 | 
			
		||||
 | 
			
		||||
#. When defining the expected input to a stubbed call, make sure the
 | 
			
		||||
   arguments are *identical*, this includes ``str`` vs. ``int`` differences.
 | 
			
		||||
 | 
			
		||||
#. Make sure your test data are completely in line with the expected inputs.
 | 
			
		||||
   Again, ``str`` vs. ``int`` or missing properties on test objects will
 | 
			
		||||
   kill your tests.
 | 
			
		||||
 | 
			
		||||
#. Make sure there's nothing amiss in your templates (particularly the
 | 
			
		||||
   ``{% url %}`` tag and its arguments). This often comes up when refactoring
 | 
			
		||||
   views or renaming context variables. It can easily result in errors that
 | 
			
		||||
   you might not stumble across while clicking around the development server.
 | 
			
		||||
 | 
			
		||||
#. Make sure you're not redirecting to views that no longer exist, e.g.
 | 
			
		||||
   the ``index`` view for a panel that got combined (such as instances &
 | 
			
		||||
   volumes).
 | 
			
		||||
 | 
			
		||||
#. Make sure your mock calls are in order before calling ``mox.ReplayAll``.
 | 
			
		||||
   The order matters.
 | 
			
		||||
 | 
			
		||||
#. Make sure you repeat any stubbed out method calls that happen more than
 | 
			
		||||
   once. They don't automatically repeat, you have to explicitly define them.
 | 
			
		||||
   While this is a nuisance, it makes you acutely aware of how many API
 | 
			
		||||
   calls are involved in a particular function.
 | 
			
		||||
 | 
			
		||||
Understanding the output from ``mox``
 | 
			
		||||
-------------------------------------
 | 
			
		||||
 | 
			
		||||
Horizon uses ``mox`` as its mocking framework of choice, and while it
 | 
			
		||||
offers many nice features, its output when a test fails can be quite
 | 
			
		||||
mysterious.
 | 
			
		||||
 | 
			
		||||
Unexpected Method Call
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This occurs when you stubbed out a piece of code, and it was subsequently
 | 
			
		||||
called in a way that you didn't specify it would be. There are two reasons
 | 
			
		||||
this tends to come up:
 | 
			
		||||
 | 
			
		||||
#. You defined the expected call, but a subtle difference crept in. This
 | 
			
		||||
   may be a string versus integer difference, a string versus unicode
 | 
			
		||||
   difference, a slightly off date/time, or passing a name instead of an id.
 | 
			
		||||
 | 
			
		||||
#. The method is actually being called *multiple times*. Since mox uses
 | 
			
		||||
   a call stack internally, it simply pops off the expected method calls to
 | 
			
		||||
   verify them. That means once a call is used once, it's gone. An easy way
 | 
			
		||||
   to see if this is the case is simply to copy and paste your method call a
 | 
			
		||||
   second time to see if the error changes. If it does, that means your method
 | 
			
		||||
   is being called more times than you think it is.
 | 
			
		||||
 | 
			
		||||
Expected Method Never Called
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
This one is the opposite of the unexpected method call. This one means you
 | 
			
		||||
tol mox to expect a call and it didn't happen. This is almost always the
 | 
			
		||||
result of an error in the conditions of the test. Using the
 | 
			
		||||
:meth:`~horizon.test.helpers.TestCase.assertNoFormErrors` and
 | 
			
		||||
:meth:`~horizon.test.helpers.TestCase.assertMessageCount` will make it readily
 | 
			
		||||
apparent what the problem is in the majority of cases. If not, then use ``pdb``
 | 
			
		||||
and start interrupting the code flow to see where things are getting off track.
 | 
			
		||||
@@ -1,556 +0,0 @@
 | 
			
		||||
===================
 | 
			
		||||
Building on Horizon
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
This tutorial covers how to use the various components in Horizon to build
 | 
			
		||||
an example dashboard and panel with a data table and tabs.
 | 
			
		||||
 | 
			
		||||
As an example, we'll build on the Nova instances API to create a new and novel
 | 
			
		||||
"visualizations" dashboard with a "flocking" panel that presents the instance
 | 
			
		||||
data in a different manner.
 | 
			
		||||
 | 
			
		||||
You can find a reference implementation of the code being described here
 | 
			
		||||
on github at https://github.com/gabrielhurley/horizon_demo.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    There are a variety of other resources which may be helpful to read first,
 | 
			
		||||
    since this is a more advanced tutorial. For example, you may want to start
 | 
			
		||||
    with the :doc:`Horizon quickstart guide </quickstart>` or the
 | 
			
		||||
    `Django tutorial`_.
 | 
			
		||||
 | 
			
		||||
    .. _Django tutorial: https://docs.djangoproject.com/en/1.4/intro/tutorial01/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Creating a dashboard
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    It is perfectly valid to create a panel without a dashboard, and
 | 
			
		||||
    incorporate it into an existing dashboard. See the section
 | 
			
		||||
    :ref:`overrides <overrides>` later in this document.
 | 
			
		||||
 | 
			
		||||
The quick version
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
Horizon provides a custom management command to create a typical base
 | 
			
		||||
dashboard structure for you. The following command generates most of the
 | 
			
		||||
boilerplate code explained below::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh -m startdash visualizations
 | 
			
		||||
 | 
			
		||||
It's still recommended that you read the rest of this section to understand
 | 
			
		||||
what that command creates and why.
 | 
			
		||||
 | 
			
		||||
Structure
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
The recommended structure for a dashboard (or panel) follows suit with the
 | 
			
		||||
typical Django application layout. We'll name our dashboard "visualizations"::
 | 
			
		||||
 | 
			
		||||
    visualizations
 | 
			
		||||
      |--__init__.py
 | 
			
		||||
      |--dashboard.py
 | 
			
		||||
      |--templates/
 | 
			
		||||
      |--static/
 | 
			
		||||
 | 
			
		||||
The ``dashboard.py`` module will contain our dashboard class for use by
 | 
			
		||||
Horizon; the ``templates`` and ``static`` directories give us homes for our
 | 
			
		||||
Django template files and static media respectively.
 | 
			
		||||
 | 
			
		||||
Within the ``static`` and ``templates`` directories it's generally good to
 | 
			
		||||
namespace your files like so::
 | 
			
		||||
 | 
			
		||||
    templates/
 | 
			
		||||
      |--visualizations/
 | 
			
		||||
    static/
 | 
			
		||||
      |--visualizations/
 | 
			
		||||
         |--css/
 | 
			
		||||
         |--js/
 | 
			
		||||
         |--img/
 | 
			
		||||
 | 
			
		||||
With those files and directories in place, we can move on to writing our
 | 
			
		||||
dashboard class.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Defining a dashboard
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
A dashboard class can be incredibly simple (about 3 lines at minimum),
 | 
			
		||||
defining nothing more than a name and a slug::
 | 
			
		||||
 | 
			
		||||
    import horizon
 | 
			
		||||
 | 
			
		||||
    class VizDash(horizon.Dashboard):
 | 
			
		||||
        name = _("Visualizations")
 | 
			
		||||
        slug = "visualizations"
 | 
			
		||||
 | 
			
		||||
In practice, a dashboard class will usually contain more information, such as a
 | 
			
		||||
list of panels, which panel is the default, and any permissions required to
 | 
			
		||||
access this dashboard::
 | 
			
		||||
 | 
			
		||||
    class VizDash(horizon.Dashboard):
 | 
			
		||||
        name = _("Visualizations")
 | 
			
		||||
        slug = "visualizations"
 | 
			
		||||
        panels = ('flocking',)
 | 
			
		||||
        default_panel = 'flocking'
 | 
			
		||||
        permissions = ('openstack.roles.admin',)
 | 
			
		||||
 | 
			
		||||
Building from that previous example we may also want to define a grouping of
 | 
			
		||||
panels which share a common theme and have a sub-heading in the navigation::
 | 
			
		||||
 | 
			
		||||
    class InstanceVisualizations(horizon.PanelGroup):
 | 
			
		||||
        slug = "instance_visualizations"
 | 
			
		||||
        name = _("Instance Visualizations")
 | 
			
		||||
        panels = ('flocking',)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class VizDash(horizon.Dashboard):
 | 
			
		||||
        name = _("Visualizations")
 | 
			
		||||
        slug = "visualizations"
 | 
			
		||||
        panels = (InstanceVisualizations,)
 | 
			
		||||
        default_panel = 'flocking'
 | 
			
		||||
        permissions = ('openstack.roles.admin',)
 | 
			
		||||
 | 
			
		||||
The ``PanelGroup`` can be added to the dashboard class' ``panels`` list
 | 
			
		||||
just like the slug of the panel can.
 | 
			
		||||
 | 
			
		||||
Once our dashboard class is complete, all we need to do is register it::
 | 
			
		||||
 | 
			
		||||
    horizon.register(VizDash)
 | 
			
		||||
 | 
			
		||||
The typical place for that would be the bottom of the ``dashboard.py`` file,
 | 
			
		||||
but it could also go elsewhere, such as in an override file (see below).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Creating a panel
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
Now that we have our dashboard written, we can also create our panel. We'll
 | 
			
		||||
call it "flocking".
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    You don't need to write a custom dashboard to add a panel. The structure
 | 
			
		||||
    here is for the sake of completeness in the tutorial.
 | 
			
		||||
 | 
			
		||||
The quick version
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
Horizon provides a custom management command to create a typical base
 | 
			
		||||
panel structure for you. The following command generates most of the
 | 
			
		||||
boilerplate code explained below::
 | 
			
		||||
 | 
			
		||||
    ./run_tests.sh -m startpanel flocking --dashboard=visualizations --target=auto
 | 
			
		||||
 | 
			
		||||
The ``dashboard`` argument is required, and tells the command which dashboard
 | 
			
		||||
this panel will be registered with. The ``target`` argument is optional, and
 | 
			
		||||
respects ``auto`` as a special value which means that the files for the panel
 | 
			
		||||
should be created inside the dashboard module as opposed to the current
 | 
			
		||||
directory (the default).
 | 
			
		||||
 | 
			
		||||
It's still recommended that you read the rest of this section to understand
 | 
			
		||||
what that command creates and why.
 | 
			
		||||
 | 
			
		||||
Structure
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
A panel is a relatively flat structure with the exception that templates
 | 
			
		||||
for a panel in a dashboard live in the dashboard's ``templates`` directory
 | 
			
		||||
rather than in the panel's ``templates`` directory. Continuing our
 | 
			
		||||
vizulaization/flocking example, let's see what the looks like::
 | 
			
		||||
 | 
			
		||||
    # stand-alone panel structure
 | 
			
		||||
    flocking/
 | 
			
		||||
      |--__init__.py
 | 
			
		||||
      |--panel.py
 | 
			
		||||
      |--urls.py
 | 
			
		||||
      |--views.py
 | 
			
		||||
      |--templates/
 | 
			
		||||
         |--flocking/
 | 
			
		||||
            |--index.html
 | 
			
		||||
 | 
			
		||||
    # panel-in-a-dashboard structure
 | 
			
		||||
    visualizations/
 | 
			
		||||
    |--__init__.py
 | 
			
		||||
    |--dashboard.py
 | 
			
		||||
    |--flocking/
 | 
			
		||||
       |--__init__.py
 | 
			
		||||
       |--panel.py
 | 
			
		||||
       |--urls.py
 | 
			
		||||
       |--views.py
 | 
			
		||||
    |--templates/
 | 
			
		||||
       |--visualizations/
 | 
			
		||||
          |--flocking/
 | 
			
		||||
             |--index.html
 | 
			
		||||
 | 
			
		||||
That follows standard Django namespacing conventions for apps and submodules
 | 
			
		||||
within apps. It also works cleanly with Django's automatic template discovery
 | 
			
		||||
in both cases.
 | 
			
		||||
 | 
			
		||||
Defining a panel
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
The ``panel.py`` file referenced above has a special meaning. Within a
 | 
			
		||||
dashboard, any module name listed in the ``panels`` attribute on the
 | 
			
		||||
dashboard class will be auto-discovered by looking for ``panel.py`` file
 | 
			
		||||
in a corresponding directory (the details are a bit magical, but have been
 | 
			
		||||
thoroughly vetted in Django's admin codebase).
 | 
			
		||||
 | 
			
		||||
Inside the ``panel.py`` module we define our ``Panel`` class::
 | 
			
		||||
 | 
			
		||||
    class Flocking(horizon.Panel):
 | 
			
		||||
        name = _("Flocking")
 | 
			
		||||
        slug = 'flocking'
 | 
			
		||||
 | 
			
		||||
Simple, right? Once we've defined it, we register it with the dashboard::
 | 
			
		||||
 | 
			
		||||
    from visualizations import dashboard
 | 
			
		||||
 | 
			
		||||
    dashboard.VizDash.register(Flocking)
 | 
			
		||||
 | 
			
		||||
Easy! There are more options you can set to customize the ``Panel`` class, but
 | 
			
		||||
it makes some intelligent guesses about what the defaults should be.
 | 
			
		||||
 | 
			
		||||
URLs
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
One of the intelligent assumptions the ``Panel`` class makes is that it can
 | 
			
		||||
find a ``urls.py`` file in your panel directory which will define a view named
 | 
			
		||||
``index`` that handles the default view for that panel. This is what your
 | 
			
		||||
``urls.py`` file might look like::
 | 
			
		||||
 | 
			
		||||
    from django.conf.urls.defaults import patterns, url
 | 
			
		||||
    from .views import IndexView
 | 
			
		||||
 | 
			
		||||
    urlpatterns = patterns('',
 | 
			
		||||
        url(r'^$', IndexView.as_view(), name='index')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
There's nothing there that isn't 100% standard Django code. This example
 | 
			
		||||
(and Horizon in general) uses the class-based views introduced in Django 1.3
 | 
			
		||||
to make code more reusable. Hence the view class is imported in the example
 | 
			
		||||
above, and the ``as_view()`` method is called in the URL pattern.
 | 
			
		||||
 | 
			
		||||
This, of course, presumes you have a view class, and takes us into the meat
 | 
			
		||||
of writing a ``Panel``.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Tables, Tabs, and Views
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
Now we get to the really exciting parts; everything before this was structural.
 | 
			
		||||
 | 
			
		||||
Starting with the high-level view, our end goal is to create a view (our
 | 
			
		||||
``IndexView`` class referenced above) which uses Horizon's ``DataTable``
 | 
			
		||||
class to display data and Horizon's ``TabGroup`` class to give us a
 | 
			
		||||
user-friendly tabbed interface in the browser.
 | 
			
		||||
 | 
			
		||||
We'll start with the table, combine that with the tabs, and then build our
 | 
			
		||||
view from the pieces.
 | 
			
		||||
 | 
			
		||||
Defining a table
 | 
			
		||||
~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Horizon provides a :class:`~horizon.tables.DataTable` class which simplifies
 | 
			
		||||
the vast majority of displaying data to an end-user. We're just going to skim
 | 
			
		||||
the surface here, but it has a tremendous number of capabilities.
 | 
			
		||||
 | 
			
		||||
In this case, we're going to be presenting data about tables, so let's start
 | 
			
		||||
defining our table (and a ``tables.py`` module::
 | 
			
		||||
 | 
			
		||||
    from horizon import tables
 | 
			
		||||
 | 
			
		||||
    class FlockingInstancesTable(tables.DataTable):
 | 
			
		||||
        host = tables.Column("OS-EXT-SRV-ATTR:host", verbose_name=_("Host"))
 | 
			
		||||
        tenant = tables.Column('tenant_name', verbose_name=_("Tenant"))
 | 
			
		||||
        user = tables.Column('user_name', verbose_name=_("user"))
 | 
			
		||||
        vcpus = tables.Column('flavor_vcpus', verbose_name=_("VCPUs"))
 | 
			
		||||
        memory = tables.Column('flavor_memory', verbose_name=_("Memory"))
 | 
			
		||||
        age = tables.Column('age', verbose_name=_("Age"))
 | 
			
		||||
 | 
			
		||||
        class Meta:
 | 
			
		||||
            name = "instances"
 | 
			
		||||
            verbose_name = _("Instances")
 | 
			
		||||
 | 
			
		||||
There are several things going on here... we created a table subclass,
 | 
			
		||||
and defined six columns on it. Each of those columns defines what attribute
 | 
			
		||||
it accesses on the instance object as the first argument, and since we like to
 | 
			
		||||
make everything translatable, we give each column a ``verbose_name`` that's
 | 
			
		||||
marked for translation.
 | 
			
		||||
 | 
			
		||||
Lastly, we added a ``Meta`` class which defines some properties about our
 | 
			
		||||
table, notably it's (translatable) verbose name, and a semi-unique "slug"-like
 | 
			
		||||
name to identify it.
 | 
			
		||||
 | 
			
		||||
.. note::
 | 
			
		||||
 | 
			
		||||
    This is a slight simplification from the reality of how the instance
 | 
			
		||||
    object is actually structured. In reality, accessing the flavor, tenant,
 | 
			
		||||
    and user attributes on it requires an additional step. This code can be
 | 
			
		||||
    seen in the example code available on github.
 | 
			
		||||
 | 
			
		||||
Defining tabs
 | 
			
		||||
~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
So we have a table, ready to receive our data. We could go straight to a view
 | 
			
		||||
from here, but we can think bigger. In this case we're also going to use
 | 
			
		||||
Horizon's :class:`~horizon.tabs.TabGroup` class. This gives us a clean,
 | 
			
		||||
no-fuss tabbed interface to display both our visualization and, optionally,
 | 
			
		||||
our data table.
 | 
			
		||||
 | 
			
		||||
First off, let's make a tab for our visualization::
 | 
			
		||||
 | 
			
		||||
    class VizTab(tabs.Tab):
 | 
			
		||||
        name = _("Visualization")
 | 
			
		||||
        slug = "viz"
 | 
			
		||||
        template_name = "visualizations/flocking/_flocking.html"
 | 
			
		||||
 | 
			
		||||
        def get_context_data(self, request):
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
This is about as simple as you can get. Since our visualization will
 | 
			
		||||
ultiimately use AJAX to load it's data we don't need to pass any context
 | 
			
		||||
to the template, and all we need to define is the name and which template
 | 
			
		||||
it should use.
 | 
			
		||||
 | 
			
		||||
Now, we also need a tab for our data table::
 | 
			
		||||
 | 
			
		||||
    from .tables import FlockingInstancesTable
 | 
			
		||||
 | 
			
		||||
    class DataTab(tabs.TableTab):
 | 
			
		||||
        name = _("Data")
 | 
			
		||||
        slug = "data"
 | 
			
		||||
        table_classes = (FlockingInstancesTable,)
 | 
			
		||||
        template_name = "horizon/common/_detail_table.html"
 | 
			
		||||
        preload = False
 | 
			
		||||
 | 
			
		||||
        def get_instances_data(self):
 | 
			
		||||
            try:
 | 
			
		||||
                instances = utils.get_instances_data(self.tab_group.request)
 | 
			
		||||
            except:
 | 
			
		||||
                instances = []
 | 
			
		||||
                exceptions.handle(self.tab_group.request,
 | 
			
		||||
                                  _('Unable to retrieve instance list.'))
 | 
			
		||||
            return instances
 | 
			
		||||
 | 
			
		||||
This tab gets a little more complicated. Foremost, it's a special type of
 | 
			
		||||
tab--one that handles data tables (and all their associated features)--and
 | 
			
		||||
it also uses the ``preload`` attribute to specify that this tab shouldn't
 | 
			
		||||
be loaded by default. It will instead be loaded via AJAX when someone clicks
 | 
			
		||||
on it, saving us on API calls in the vast majority of cases.
 | 
			
		||||
 | 
			
		||||
Lastly, this code introduces the concept of error handling in Horizon.
 | 
			
		||||
The :func:`horizon.exceptions.handle` function is a centralized error
 | 
			
		||||
handling mechanism that takes all the guess-work and inconsistency out of
 | 
			
		||||
dealing with exceptions from the API. Use it everywhere.
 | 
			
		||||
 | 
			
		||||
Tying it together in a view
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
There are lots of pre-built class-based views in Horizon. We try to provide
 | 
			
		||||
starting points for all the common combinations of components.
 | 
			
		||||
 | 
			
		||||
In this case we want a starting view type that works with both tabs and
 | 
			
		||||
tables... that'd be the :class:`~horizon.tabs.TabbedTableView` class. It takes
 | 
			
		||||
the best of the dynamic delayed-loading capabilities tab groups provide and
 | 
			
		||||
mixes in the actions and AJAX-updating that tables are capable of with almost
 | 
			
		||||
no work on the user's end. Let's see what the code would look like::
 | 
			
		||||
 | 
			
		||||
    from .tables import FlockingInstancesTable
 | 
			
		||||
    from .tabs import FlockingTabs
 | 
			
		||||
 | 
			
		||||
    class IndexView(tabs.TabbedTableView):
 | 
			
		||||
        tab_group_class = FlockingTabs
 | 
			
		||||
        table_class = FlockingInstancesTable
 | 
			
		||||
        template_name = 'visualizations/flocking/index.html'
 | 
			
		||||
 | 
			
		||||
That would get us 100% of the way to what we need if this particular
 | 
			
		||||
demo didn't involve an extra AJAX call to fetch back our visualization
 | 
			
		||||
data via AJAX. Because of that we need to override the class' ``get()``
 | 
			
		||||
method to return the right data for an AJAX call::
 | 
			
		||||
 | 
			
		||||
    from .tables import FlockingInstancesTable
 | 
			
		||||
    from .tabs import FlockingTabs
 | 
			
		||||
 | 
			
		||||
    class IndexView(tabs.TabbedTableView):
 | 
			
		||||
        tab_group_class = FlockingTabs
 | 
			
		||||
        table_class = FlockingInstancesTable
 | 
			
		||||
        template_name = 'visualizations/flocking/index.html'
 | 
			
		||||
 | 
			
		||||
        def get(self, request, *args, **kwargs):
 | 
			
		||||
            if self.request.is_ajax() and self.request.GET.get("json", False):
 | 
			
		||||
                try:
 | 
			
		||||
                    instances = utils.get_instances_data(self.request)
 | 
			
		||||
                except:
 | 
			
		||||
                    instances = []
 | 
			
		||||
                    exceptions.handle(request,
 | 
			
		||||
                                      _('Unable to retrieve instance list.'))
 | 
			
		||||
                data = json.dumps([i._apiresource._info for i in instances])
 | 
			
		||||
                return http.HttpResponse(data)
 | 
			
		||||
            else:
 | 
			
		||||
                return super(IndexView, self).get(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
In this instance, we override the ``get()`` method such that if it's an
 | 
			
		||||
AJAX request and has the GET parameter we're looking for, it returns our
 | 
			
		||||
instance data in JSON format; otherwise it simply returns the view function
 | 
			
		||||
as per the usual.
 | 
			
		||||
 | 
			
		||||
The template
 | 
			
		||||
~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
We need three templates here: one for the view, and one for each of our two
 | 
			
		||||
tabs. The view template (in this case) can inherit from one of the other
 | 
			
		||||
dashboards::
 | 
			
		||||
 | 
			
		||||
    {% extends 'base.html' %}
 | 
			
		||||
    {% load i18n %}
 | 
			
		||||
    {% block title %}{% trans "Flocking" %}{% endblock %}
 | 
			
		||||
 | 
			
		||||
    {% block page_header %}
 | 
			
		||||
      {% include "horizon/common/_page_header.html" with title=_("Flocking") %}
 | 
			
		||||
    {% endblock page_header %}
 | 
			
		||||
 | 
			
		||||
    {% block main %}
 | 
			
		||||
    <div class="row-fluid">
 | 
			
		||||
      <div class="span12">
 | 
			
		||||
      {{ tab_group.render }}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
 | 
			
		||||
This gives us a custom page title, a header, and render our tab group provided
 | 
			
		||||
by the view.
 | 
			
		||||
 | 
			
		||||
For the tabs, the one using the table is handled by a reusable template,
 | 
			
		||||
``"horizon/common/_detail_table.html"``. This is appropriate for any tab that
 | 
			
		||||
only displays a single table.
 | 
			
		||||
 | 
			
		||||
The second tab is a bit of secret sauce for the visualization, but it's still
 | 
			
		||||
quite simple and can be investigated in the github example.
 | 
			
		||||
 | 
			
		||||
The takeaway here is that each tab needs a template associated with it.
 | 
			
		||||
 | 
			
		||||
With all our code in place, the only thing left to do is to integrated it into
 | 
			
		||||
our OpenStack Dashboard site.
 | 
			
		||||
 | 
			
		||||
Setting up a project
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
The vast majority of people will just customize the OpenStack Dashboard
 | 
			
		||||
example project that ships with Horizon. As such, this tutorial will
 | 
			
		||||
start from that and just illustrate the bits that can be customized.
 | 
			
		||||
 | 
			
		||||
Structure
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
A site built on Horizon takes the form of a very typical Django project::
 | 
			
		||||
 | 
			
		||||
    site/
 | 
			
		||||
      |--__init__.py
 | 
			
		||||
      |--manage.py
 | 
			
		||||
      |--demo_dashboard/
 | 
			
		||||
         |--__init__.py
 | 
			
		||||
         |--models.py  # required for Django even if unused
 | 
			
		||||
         |--settings.py
 | 
			
		||||
         |--templates/
 | 
			
		||||
         |--static/
 | 
			
		||||
 | 
			
		||||
The key bits here are that ``demo_dashboard`` is on our python path, and that
 | 
			
		||||
the `settings.py`` file here will contain our customized Horizon config.
 | 
			
		||||
 | 
			
		||||
The settings file
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
There are several key things you will generally want to customiz in your
 | 
			
		||||
site's settings file: specifying custom dashboards and panels, catching your
 | 
			
		||||
client's exception classes, and (possibly) specifying a file for advanced
 | 
			
		||||
overrides.
 | 
			
		||||
 | 
			
		||||
Specifying dashboards
 | 
			
		||||
~~~~~~~~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
The most basic thing to do is to add your own custom dashboard using the
 | 
			
		||||
``HORIZON_CONFIG`` dictionary in the settings file::
 | 
			
		||||
 | 
			
		||||
    HORIZON_CONFIG = {
 | 
			
		||||
        'dashboards': ('project', 'admin', 'settings',),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
Please note, the dashboards also must be added to settings.py::
 | 
			
		||||
    INSTALLED_APPS = (
 | 
			
		||||
        'openstack_dashboard',
 | 
			
		||||
        ...
 | 
			
		||||
        'horizon',
 | 
			
		||||
        'openstack_dashboard.dashboards.project',
 | 
			
		||||
        'openstack_dashboard.dashboards.admin',
 | 
			
		||||
        'openstack_dashboard.dashboards.settings',
 | 
			
		||||
        ...
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
In this case, we've taken the default Horizon ``'dashboards'`` config and
 | 
			
		||||
added our ``visualizations`` dashboard to it. Note that the name here is the
 | 
			
		||||
name of the dashboard's module on the python path. It will find our
 | 
			
		||||
``dashboard.py`` file inside of it and load both the dashboard and its panels
 | 
			
		||||
automatically from there.
 | 
			
		||||
 | 
			
		||||
Error handling
 | 
			
		||||
~~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
Adding custom error handler for your API client is quite easy. While it's not
 | 
			
		||||
necessary for this example, it would be done by customizing the
 | 
			
		||||
``'exceptions'`` value in the ``HORIZON_CONFIG`` dictionary::
 | 
			
		||||
 | 
			
		||||
    import my_api.exceptions as my_api
 | 
			
		||||
 | 
			
		||||
    'exceptions': {'recoverable': [my_api.Error,
 | 
			
		||||
                                   my_api.ClientConnectionError],
 | 
			
		||||
                   'not_found': [my_api.NotFound],
 | 
			
		||||
                   'unauthorized': [my_api.NotAuthorized]},
 | 
			
		||||
 | 
			
		||||
.. _overrides:
 | 
			
		||||
 | 
			
		||||
Override file
 | 
			
		||||
~~~~~~~~~~~~~
 | 
			
		||||
 | 
			
		||||
The override file is the "god-mode" dashboard editor. The hook for this file
 | 
			
		||||
sits right between the automatic discovery mechanisms and the final setup
 | 
			
		||||
routines for the entire site. By specifying an override file you can alter
 | 
			
		||||
any behavior you like in existing code. This tutorial won't go in-depth,
 | 
			
		||||
but let's just say that with great power comes great responsibility.
 | 
			
		||||
 | 
			
		||||
To specify am override file, you set the ``'customization_module'`` value in
 | 
			
		||||
the ``HORIZON_CONFIG`` dictionary to the dotted python path of your
 | 
			
		||||
override module::
 | 
			
		||||
 | 
			
		||||
    HORIZON_CONFIG = {
 | 
			
		||||
        'customization_module': 'demo_dashboard.overrides'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
This file is capable of adding dashboards, adding panels to existing
 | 
			
		||||
dashboards, renaming existing dashboards and panels (or altering other
 | 
			
		||||
attributes on them), removing panels from existing dashboards, and so on.
 | 
			
		||||
 | 
			
		||||
We could say more, but it only gets more dangerous...
 | 
			
		||||
 | 
			
		||||
Conclusion
 | 
			
		||||
==========
 | 
			
		||||
 | 
			
		||||
Sadly, the cake was a lie. The information in this "tutorial" was never
 | 
			
		||||
meant to leave you with a working dashboard. It's close. But there's
 | 
			
		||||
waaaaaay too much javascript involved in the visualization to cover it all
 | 
			
		||||
here, and it'd be irrelevant to Horizon anyway.
 | 
			
		||||
 | 
			
		||||
If you want to see the finished product, check out the github example
 | 
			
		||||
referenced at the beginning of this tutorial.
 | 
			
		||||
 | 
			
		||||
Clone the repository and simply run ``./run_tests.sh --runserver``. That'll
 | 
			
		||||
give you a 100% working dashboard that uses every technique in this tutorial.
 | 
			
		||||
 | 
			
		||||
What you've learned here, however, is the fundamentals of almost everything
 | 
			
		||||
you need to know to start writing interfaces for your own project based on the
 | 
			
		||||
components Horizon provides.
 | 
			
		||||
 | 
			
		||||
If you have questions, or feedback on how this tutorial could be improved,
 | 
			
		||||
please feel free to pass them along!
 | 
			
		||||
@@ -1,57 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
""" The Horizon interface.
 | 
			
		||||
 | 
			
		||||
Contains the core Horizon classes--:class:`~horizon.Dashboard` and
 | 
			
		||||
:class:`horizon.Panel`--the dynamic URLconf for Horizon, and common interface
 | 
			
		||||
methods like :func:`~horizon.register` and :func:`~horizon.unregister`.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
# Because this module is compiled by setup.py before Django may be installed
 | 
			
		||||
# in the environment we try importing Django and issue a warning but move on
 | 
			
		||||
# should that fail.
 | 
			
		||||
Horizon = None
 | 
			
		||||
try:
 | 
			
		||||
    from horizon.base import Dashboard
 | 
			
		||||
    from horizon.base import Horizon
 | 
			
		||||
    from horizon.base import Panel
 | 
			
		||||
    from horizon.base import PanelGroup
 | 
			
		||||
except ImportError:
 | 
			
		||||
    import warnings
 | 
			
		||||
 | 
			
		||||
    def simple_warn(message, category, filename, lineno, file=None, line=None):
 | 
			
		||||
        return '%s: %s' % (category.__name__, message)
 | 
			
		||||
 | 
			
		||||
    msg = ("Could not import Horizon dependencies. "
 | 
			
		||||
           "This is normal during installation.\n")
 | 
			
		||||
    warnings.formatwarning = simple_warn
 | 
			
		||||
    warnings.warn(msg, Warning)
 | 
			
		||||
 | 
			
		||||
if Horizon:
 | 
			
		||||
    register = Horizon.register
 | 
			
		||||
    unregister = Horizon.unregister
 | 
			
		||||
    get_absolute_url = Horizon.get_absolute_url
 | 
			
		||||
    get_user_home = Horizon.get_user_home
 | 
			
		||||
    get_dashboard = Horizon.get_dashboard
 | 
			
		||||
    get_default_dashboard = Horizon.get_default_dashboard
 | 
			
		||||
    get_dashboards = Horizon.get_dashboards
 | 
			
		||||
    urls = Horizon._lazy_urls
 | 
			
		||||
 | 
			
		||||
# silence flake8 about unused imports here:
 | 
			
		||||
assert Dashboard
 | 
			
		||||
assert Panel
 | 
			
		||||
assert PanelGroup
 | 
			
		||||
							
								
								
									
										803
									
								
								horizon/base.py
									
									
									
									
									
								
							
							
						
						
									
										803
									
								
								horizon/base.py
									
									
									
									
									
								
							@@ -1,803 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Contains the core classes and functionality that makes Horizon what it is.
 | 
			
		||||
This module is considered internal, and should not be relied on directly.
 | 
			
		||||
 | 
			
		||||
Public APIs are made available through the :mod:`horizon` module and
 | 
			
		||||
the classes contained therein.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import collections
 | 
			
		||||
import copy
 | 
			
		||||
import inspect
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.conf.urls.defaults import include
 | 
			
		||||
from django.conf.urls.defaults import patterns
 | 
			
		||||
from django.conf.urls.defaults import url
 | 
			
		||||
from django.core.exceptions import ImproperlyConfigured
 | 
			
		||||
from django.core.urlresolvers import reverse
 | 
			
		||||
from django.utils.datastructures import SortedDict
 | 
			
		||||
from django.utils.functional import SimpleLazyObject
 | 
			
		||||
from django.utils.importlib import import_module
 | 
			
		||||
from django.utils.module_loading import module_has_submodule
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from horizon import conf
 | 
			
		||||
from horizon.decorators import _current_component
 | 
			
		||||
from horizon.decorators import require_auth
 | 
			
		||||
from horizon.decorators import require_perms
 | 
			
		||||
from horizon import loaders
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _decorate_urlconf(urlpatterns, decorator, *args, **kwargs):
 | 
			
		||||
    for pattern in urlpatterns:
 | 
			
		||||
        if getattr(pattern, 'callback', None):
 | 
			
		||||
            pattern._callback = decorator(pattern.callback, *args, **kwargs)
 | 
			
		||||
        if getattr(pattern, 'url_patterns', []):
 | 
			
		||||
            _decorate_urlconf(pattern.url_patterns, decorator, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NotRegistered(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HorizonComponent(object):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super(HorizonComponent, self).__init__()
 | 
			
		||||
        if not self.slug:
 | 
			
		||||
            raise ImproperlyConfigured('Every %s must have a slug.'
 | 
			
		||||
                                       % self.__class__)
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        name = getattr(self, 'name', u"Unnamed %s" % self.__class__.__name__)
 | 
			
		||||
        return unicode(name)
 | 
			
		||||
 | 
			
		||||
    def _get_default_urlpatterns(self):
 | 
			
		||||
        package_string = '.'.join(self.__module__.split('.')[:-1])
 | 
			
		||||
        if getattr(self, 'urls', None):
 | 
			
		||||
            try:
 | 
			
		||||
                mod = import_module('.%s' % self.urls, package_string)
 | 
			
		||||
            except ImportError:
 | 
			
		||||
                mod = import_module(self.urls)
 | 
			
		||||
            urlpatterns = mod.urlpatterns
 | 
			
		||||
        else:
 | 
			
		||||
            # Try importing a urls.py from the dashboard package
 | 
			
		||||
            if module_has_submodule(import_module(package_string), 'urls'):
 | 
			
		||||
                urls_mod = import_module('.urls', package_string)
 | 
			
		||||
                urlpatterns = urls_mod.urlpatterns
 | 
			
		||||
            else:
 | 
			
		||||
                urlpatterns = patterns('')
 | 
			
		||||
        return urlpatterns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Registry(object):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self._registry = {}
 | 
			
		||||
        if not getattr(self, '_registerable_class', None):
 | 
			
		||||
            raise ImproperlyConfigured('Subclasses of Registry must set a '
 | 
			
		||||
                                       '"_registerable_class" property.')
 | 
			
		||||
 | 
			
		||||
    def _register(self, cls):
 | 
			
		||||
        """Registers the given class.
 | 
			
		||||
 | 
			
		||||
        If the specified class is already registered then it is ignored.
 | 
			
		||||
        """
 | 
			
		||||
        if not inspect.isclass(cls):
 | 
			
		||||
            raise ValueError('Only classes may be registered.')
 | 
			
		||||
        elif not issubclass(cls, self._registerable_class):
 | 
			
		||||
            raise ValueError('Only %s classes or subclasses may be registered.'
 | 
			
		||||
                             % self._registerable_class.__name__)
 | 
			
		||||
 | 
			
		||||
        if cls not in self._registry:
 | 
			
		||||
            cls._registered_with = self
 | 
			
		||||
            self._registry[cls] = cls()
 | 
			
		||||
 | 
			
		||||
        return self._registry[cls]
 | 
			
		||||
 | 
			
		||||
    def _unregister(self, cls):
 | 
			
		||||
        """Unregisters the given class.
 | 
			
		||||
 | 
			
		||||
        If the specified class isn't registered, ``NotRegistered`` will
 | 
			
		||||
        be raised.
 | 
			
		||||
        """
 | 
			
		||||
        if not issubclass(cls, self._registerable_class):
 | 
			
		||||
            raise ValueError('Only %s classes or subclasses may be '
 | 
			
		||||
                             'unregistered.' % self._registerable_class)
 | 
			
		||||
 | 
			
		||||
        if cls not in self._registry.keys():
 | 
			
		||||
            raise NotRegistered('%s is not registered' % cls)
 | 
			
		||||
 | 
			
		||||
        del self._registry[cls]
 | 
			
		||||
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _registered(self, cls):
 | 
			
		||||
        if inspect.isclass(cls) and issubclass(cls, self._registerable_class):
 | 
			
		||||
            found = self._registry.get(cls, None)
 | 
			
		||||
            if found:
 | 
			
		||||
                return found
 | 
			
		||||
        else:
 | 
			
		||||
            # Allow for fetching by slugs as well.
 | 
			
		||||
            for registered in self._registry.values():
 | 
			
		||||
                if registered.slug == cls:
 | 
			
		||||
                    return registered
 | 
			
		||||
        class_name = self._registerable_class.__name__
 | 
			
		||||
        if hasattr(self, "_registered_with"):
 | 
			
		||||
            parent = self._registered_with._registerable_class.__name__
 | 
			
		||||
            raise NotRegistered('%(type)s with slug "%(slug)s" is not '
 | 
			
		||||
                                'registered with %(parent)s "%(name)s".'
 | 
			
		||||
                                    % {"type": class_name,
 | 
			
		||||
                                       "slug": cls,
 | 
			
		||||
                                       "parent": parent,
 | 
			
		||||
                                       "name": self.slug})
 | 
			
		||||
        else:
 | 
			
		||||
            slug = getattr(cls, "slug", cls)
 | 
			
		||||
            raise NotRegistered('%(type)s with slug "%(slug)s" is not '
 | 
			
		||||
                                'registered.' % {"type": class_name,
 | 
			
		||||
                                                 "slug": slug})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Panel(HorizonComponent):
 | 
			
		||||
    """ A base class for defining Horizon dashboard panels.
 | 
			
		||||
 | 
			
		||||
    All Horizon dashboard panels should extend from this class. It provides
 | 
			
		||||
    the appropriate hooks for automatically constructing URLconfs, and
 | 
			
		||||
    providing permission-based access control.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: name
 | 
			
		||||
 | 
			
		||||
        The name of the panel. This will be displayed in the
 | 
			
		||||
        auto-generated navigation and various other places.
 | 
			
		||||
        Default: ``''``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: slug
 | 
			
		||||
 | 
			
		||||
        A unique "short name" for the panel. The slug is used as
 | 
			
		||||
        a component of the URL path for the panel. Default: ``''``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: permissions
 | 
			
		||||
 | 
			
		||||
        A list of permission names, all of which a user must possess in order
 | 
			
		||||
        to access any view associated with this panel. This attribute
 | 
			
		||||
        is combined cumulatively with any permissions required on the
 | 
			
		||||
        ``Dashboard`` class with which it is registered.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: urls
 | 
			
		||||
 | 
			
		||||
        Path to a URLconf of views for this panel using dotted Python
 | 
			
		||||
        notation. If no value is specified, a file called ``urls.py``
 | 
			
		||||
        living in the same package as the ``panel.py`` file is used.
 | 
			
		||||
        Default: ``None``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: nav
 | 
			
		||||
    .. method:: nav(context)
 | 
			
		||||
 | 
			
		||||
        The ``nav`` attribute can be either boolean value or a callable
 | 
			
		||||
        which accepts a ``RequestContext`` object as a single argument
 | 
			
		||||
        to control whether or not this panel should appear in
 | 
			
		||||
        automatically-generated navigation. Default: ``True``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: index_url_name
 | 
			
		||||
 | 
			
		||||
        The ``name`` argument for the URL pattern which corresponds to
 | 
			
		||||
        the index view for this ``Panel``. This is the view that
 | 
			
		||||
        :meth:`.Panel.get_absolute_url` will attempt to reverse.
 | 
			
		||||
    """
 | 
			
		||||
    name = ''
 | 
			
		||||
    slug = ''
 | 
			
		||||
    urls = None
 | 
			
		||||
    nav = True
 | 
			
		||||
    index_url_name = "index"
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<Panel: %s>" % self.slug
 | 
			
		||||
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        """ Returns the default URL for this panel.
 | 
			
		||||
 | 
			
		||||
        The default URL is defined as the URL pattern with ``name="index"`` in
 | 
			
		||||
        the URLconf for this panel.
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            return reverse('horizon:%s:%s:%s' % (self._registered_with.slug,
 | 
			
		||||
                                                 self.slug,
 | 
			
		||||
                                                 self.index_url_name))
 | 
			
		||||
        except Exception as exc:
 | 
			
		||||
            # Logging here since this will often be called in a template
 | 
			
		||||
            # where the exception would be hidden.
 | 
			
		||||
            LOG.info("Error reversing absolute URL for %s: %s" % (self, exc))
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def _decorated_urls(self):
 | 
			
		||||
        urlpatterns = self._get_default_urlpatterns()
 | 
			
		||||
 | 
			
		||||
        # Apply access controls to all views in the patterns
 | 
			
		||||
        permissions = getattr(self, 'permissions', [])
 | 
			
		||||
        _decorate_urlconf(urlpatterns, require_perms, permissions)
 | 
			
		||||
        _decorate_urlconf(urlpatterns, _current_component, panel=self)
 | 
			
		||||
 | 
			
		||||
        # Return the three arguments to django.conf.urls.defaults.include
 | 
			
		||||
        return urlpatterns, self.slug, self.slug
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PanelGroup(object):
 | 
			
		||||
    """ A container for a set of :class:`~horizon.Panel` classes.
 | 
			
		||||
 | 
			
		||||
    When iterated, it will yield each of the ``Panel`` instances it
 | 
			
		||||
    contains.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: slug
 | 
			
		||||
 | 
			
		||||
        A unique string to identify this panel group. Required.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: name
 | 
			
		||||
 | 
			
		||||
        A user-friendly name which will be used as the group heading in
 | 
			
		||||
        places such as the navigation. Default: ``None``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: panels
 | 
			
		||||
 | 
			
		||||
        A list of panel module names which should be contained within this
 | 
			
		||||
        grouping.
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, dashboard, slug=None, name=None, panels=None):
 | 
			
		||||
        self.dashboard = dashboard
 | 
			
		||||
        self.slug = slug or getattr(self, "slug", "default")
 | 
			
		||||
        self.name = name or getattr(self, "name", None)
 | 
			
		||||
        # Our panels must be mutable so it can be extended by others.
 | 
			
		||||
        self.panels = list(panels or getattr(self, "panels", []))
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<%s: %s>" % (self.__class__.__name__, self.slug)
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        panel_instances = []
 | 
			
		||||
        for name in self.panels:
 | 
			
		||||
            try:
 | 
			
		||||
                panel_instances.append(self.dashboard.get_panel(name))
 | 
			
		||||
            except NotRegistered as e:
 | 
			
		||||
                LOG.debug(e)
 | 
			
		||||
        return iter(panel_instances)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Dashboard(Registry, HorizonComponent):
 | 
			
		||||
    """ A base class for defining Horizon dashboards.
 | 
			
		||||
 | 
			
		||||
    All Horizon dashboards should extend from this base class. It provides the
 | 
			
		||||
    appropriate hooks for automatic discovery of :class:`~horizon.Panel`
 | 
			
		||||
    modules, automatically constructing URLconfs, and providing
 | 
			
		||||
    permission-based access control.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: name
 | 
			
		||||
 | 
			
		||||
        The name of the dashboard. This will be displayed in the
 | 
			
		||||
        auto-generated navigation and various other places.
 | 
			
		||||
        Default: ``''``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: slug
 | 
			
		||||
 | 
			
		||||
        A unique "short name" for the dashboard. The slug is used as
 | 
			
		||||
        a component of the URL path for the dashboard. Default: ``''``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: panels
 | 
			
		||||
 | 
			
		||||
        The ``panels`` attribute can be either a flat list containing the name
 | 
			
		||||
        of each panel **module**  which should be loaded as part of this
 | 
			
		||||
        dashboard, or a list of :class:`~horizon.PanelGroup` classes which
 | 
			
		||||
        define groups of panels as in the following example::
 | 
			
		||||
 | 
			
		||||
            class SystemPanels(horizon.PanelGroup):
 | 
			
		||||
                slug = "syspanel"
 | 
			
		||||
                name = _("System Panel")
 | 
			
		||||
                panels = ('overview', 'instances', ...)
 | 
			
		||||
 | 
			
		||||
            class Syspanel(horizon.Dashboard):
 | 
			
		||||
                panels = (SystemPanels,)
 | 
			
		||||
 | 
			
		||||
        Automatically generated navigation will use the order of the
 | 
			
		||||
        modules in this attribute.
 | 
			
		||||
 | 
			
		||||
        Default: ``[]``.
 | 
			
		||||
 | 
			
		||||
        .. warning::
 | 
			
		||||
 | 
			
		||||
            The values for this attribute should not correspond to the
 | 
			
		||||
            :attr:`~.Panel.name` attributes of the ``Panel`` classes.
 | 
			
		||||
            They should be the names of the Python modules in which the
 | 
			
		||||
            ``panel.py`` files live. This is used for the automatic
 | 
			
		||||
            loading and registration of ``Panel`` classes much like
 | 
			
		||||
            Django's ``ModelAdmin`` machinery.
 | 
			
		||||
 | 
			
		||||
            Panel modules must be listed in ``panels`` in order to be
 | 
			
		||||
            discovered by the automatic registration mechanism.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: default_panel
 | 
			
		||||
 | 
			
		||||
        The name of the panel which should be treated as the default
 | 
			
		||||
        panel for the dashboard, i.e. when you visit the root URL
 | 
			
		||||
        for this dashboard, that's the panel that is displayed.
 | 
			
		||||
        Default: ``None``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: permissions
 | 
			
		||||
 | 
			
		||||
        A list of permission names, all of which a user must possess in order
 | 
			
		||||
        to access any panel registered with this dashboard. This attribute
 | 
			
		||||
        is combined cumulatively with any permissions required on individual
 | 
			
		||||
        :class:`~horizon.Panel` classes.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: urls
 | 
			
		||||
 | 
			
		||||
        Optional path to a URLconf of additional views for this dashboard
 | 
			
		||||
        which are not connected to specific panels. Default: ``None``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: nav
 | 
			
		||||
 | 
			
		||||
        Optional boolean to control whether or not this dashboard should
 | 
			
		||||
        appear in automatically-generated navigation. Default: ``True``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: supports_tenants
 | 
			
		||||
 | 
			
		||||
        Optional boolean that indicates whether or not this dashboard includes
 | 
			
		||||
        support for projects/tenants. If set to ``True`` this dashboard's
 | 
			
		||||
        navigation will include a UI element that allows the user to select
 | 
			
		||||
        project/tenant. Default: ``False``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: public
 | 
			
		||||
 | 
			
		||||
        Boolean value to determine whether this dashboard can be viewed
 | 
			
		||||
        without being logged in. Defaults to ``False``.
 | 
			
		||||
    """
 | 
			
		||||
    _registerable_class = Panel
 | 
			
		||||
    name = ''
 | 
			
		||||
    slug = ''
 | 
			
		||||
    urls = None
 | 
			
		||||
    panels = []
 | 
			
		||||
    default_panel = None
 | 
			
		||||
    nav = True
 | 
			
		||||
    supports_tenants = False
 | 
			
		||||
    public = False
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return "<Dashboard: %s>" % self.slug
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super(Dashboard, self).__init__(*args, **kwargs)
 | 
			
		||||
        self._panel_groups = None
 | 
			
		||||
 | 
			
		||||
    def get_panel(self, panel):
 | 
			
		||||
        """
 | 
			
		||||
        Returns the specified :class:`~horizon.Panel` instance registered
 | 
			
		||||
        with this dashboard.
 | 
			
		||||
        """
 | 
			
		||||
        return self._registered(panel)
 | 
			
		||||
 | 
			
		||||
    def get_panels(self):
 | 
			
		||||
        """
 | 
			
		||||
        Returns the :class:`~horizon.Panel` instances registered with this
 | 
			
		||||
        dashboard in order, without any panel groupings.
 | 
			
		||||
        """
 | 
			
		||||
        all_panels = []
 | 
			
		||||
        panel_groups = self.get_panel_groups()
 | 
			
		||||
        for panel_group in panel_groups.values():
 | 
			
		||||
            all_panels.extend(panel_group)
 | 
			
		||||
        return all_panels
 | 
			
		||||
 | 
			
		||||
    def get_panel_group(self, slug):
 | 
			
		||||
        return self._panel_groups[slug]
 | 
			
		||||
 | 
			
		||||
    def get_panel_groups(self):
 | 
			
		||||
        registered = copy.copy(self._registry)
 | 
			
		||||
        panel_groups = []
 | 
			
		||||
 | 
			
		||||
        # Gather our known panels
 | 
			
		||||
        if self._panel_groups is not None:
 | 
			
		||||
            for panel_group in self._panel_groups.values():
 | 
			
		||||
                for panel in panel_group:
 | 
			
		||||
                    registered.pop(panel.__class__)
 | 
			
		||||
                panel_groups.append((panel_group.slug, panel_group))
 | 
			
		||||
 | 
			
		||||
        # Deal with leftovers (such as add-on registrations)
 | 
			
		||||
        if len(registered):
 | 
			
		||||
            slugs = [panel.slug for panel in registered.values()]
 | 
			
		||||
            new_group = PanelGroup(self,
 | 
			
		||||
                                   slug="other",
 | 
			
		||||
                                   name=_("Other"),
 | 
			
		||||
                                   panels=slugs)
 | 
			
		||||
            panel_groups.append((new_group.slug, new_group))
 | 
			
		||||
        return SortedDict(panel_groups)
 | 
			
		||||
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        """ Returns the default URL for this dashboard.
 | 
			
		||||
 | 
			
		||||
        The default URL is defined as the URL pattern with ``name="index"``
 | 
			
		||||
        in the URLconf for the :class:`~horizon.Panel` specified by
 | 
			
		||||
        :attr:`~horizon.Dashboard.default_panel`.
 | 
			
		||||
        """
 | 
			
		||||
        try:
 | 
			
		||||
            return self._registered(self.default_panel).get_absolute_url()
 | 
			
		||||
        except:
 | 
			
		||||
            # Logging here since this will often be called in a template
 | 
			
		||||
            # where the exception would be hidden.
 | 
			
		||||
            LOG.exception("Error reversing absolute URL for %s." % self)
 | 
			
		||||
            raise
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def _decorated_urls(self):
 | 
			
		||||
        urlpatterns = self._get_default_urlpatterns()
 | 
			
		||||
 | 
			
		||||
        default_panel = None
 | 
			
		||||
 | 
			
		||||
        # Add in each panel's views except for the default view.
 | 
			
		||||
        for panel in self._registry.values():
 | 
			
		||||
            if panel.slug == self.default_panel:
 | 
			
		||||
                default_panel = panel
 | 
			
		||||
                continue
 | 
			
		||||
            urlpatterns += patterns('',
 | 
			
		||||
                    url(r'^%s/' % panel.slug, include(panel._decorated_urls)))
 | 
			
		||||
        # Now the default view, which should come last
 | 
			
		||||
        if not default_panel:
 | 
			
		||||
            raise NotRegistered('The default panel "%s" is not registered.'
 | 
			
		||||
                                % self.default_panel)
 | 
			
		||||
        urlpatterns += patterns('',
 | 
			
		||||
                url(r'', include(default_panel._decorated_urls)))
 | 
			
		||||
 | 
			
		||||
        # Require login if not public.
 | 
			
		||||
        if not self.public:
 | 
			
		||||
            _decorate_urlconf(urlpatterns, require_auth)
 | 
			
		||||
        # Apply access controls to all views in the patterns
 | 
			
		||||
        permissions = getattr(self, 'permissions', [])
 | 
			
		||||
        _decorate_urlconf(urlpatterns, require_perms, permissions)
 | 
			
		||||
        _decorate_urlconf(urlpatterns, _current_component, dashboard=self)
 | 
			
		||||
 | 
			
		||||
        # Return the three arguments to django.conf.urls.defaults.include
 | 
			
		||||
        return urlpatterns, self.slug, self.slug
 | 
			
		||||
 | 
			
		||||
    def _autodiscover(self):
 | 
			
		||||
        """ Discovers panels to register from the current dashboard module. """
 | 
			
		||||
        if getattr(self, "_autodiscover_complete", False):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        panels_to_discover = []
 | 
			
		||||
        panel_groups = []
 | 
			
		||||
        # If we have a flat iterable of panel names, wrap it again so
 | 
			
		||||
        # we have a consistent structure for the next step.
 | 
			
		||||
        if all([isinstance(i, basestring) for i in self.panels]):
 | 
			
		||||
            self.panels = [self.panels]
 | 
			
		||||
 | 
			
		||||
        # Now iterate our panel sets.
 | 
			
		||||
        for panel_set in self.panels:
 | 
			
		||||
            # Instantiate PanelGroup classes.
 | 
			
		||||
            if not isinstance(panel_set, collections.Iterable) and \
 | 
			
		||||
                    issubclass(panel_set, PanelGroup):
 | 
			
		||||
                panel_group = panel_set(self)
 | 
			
		||||
            # Check for nested tuples, and convert them to PanelGroups
 | 
			
		||||
            elif not isinstance(panel_set, PanelGroup):
 | 
			
		||||
                panel_group = PanelGroup(self, panels=panel_set)
 | 
			
		||||
 | 
			
		||||
            # Put our results into their appropriate places
 | 
			
		||||
            panels_to_discover.extend(panel_group.panels)
 | 
			
		||||
            panel_groups.append((panel_group.slug, panel_group))
 | 
			
		||||
 | 
			
		||||
        self._panel_groups = SortedDict(panel_groups)
 | 
			
		||||
 | 
			
		||||
        # Do the actual discovery
 | 
			
		||||
        package = '.'.join(self.__module__.split('.')[:-1])
 | 
			
		||||
        mod = import_module(package)
 | 
			
		||||
        for panel in panels_to_discover:
 | 
			
		||||
            try:
 | 
			
		||||
                before_import_registry = copy.copy(self._registry)
 | 
			
		||||
                import_module('.%s.panel' % panel, package)
 | 
			
		||||
            except:
 | 
			
		||||
                self._registry = before_import_registry
 | 
			
		||||
                if module_has_submodule(mod, panel):
 | 
			
		||||
                    raise
 | 
			
		||||
        self._autodiscover_complete = True
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def register(cls, panel):
 | 
			
		||||
        """ Registers a :class:`~horizon.Panel` with this dashboard. """
 | 
			
		||||
        panel_class = Horizon.register_panel(cls, panel)
 | 
			
		||||
        # Support template loading from panel template directories.
 | 
			
		||||
        panel_mod = import_module(panel.__module__)
 | 
			
		||||
        panel_dir = os.path.dirname(panel_mod.__file__)
 | 
			
		||||
        template_dir = os.path.join(panel_dir, "templates")
 | 
			
		||||
        if os.path.exists(template_dir):
 | 
			
		||||
            key = os.path.join(cls.slug, panel.slug)
 | 
			
		||||
            loaders.panel_template_dirs[key] = template_dir
 | 
			
		||||
        return panel_class
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def unregister(cls, panel):
 | 
			
		||||
        """ Unregisters a :class:`~horizon.Panel` from this dashboard. """
 | 
			
		||||
        success = Horizon.unregister_panel(cls, panel)
 | 
			
		||||
        if success:
 | 
			
		||||
            # Remove the panel's template directory.
 | 
			
		||||
            key = os.path.join(cls.slug, panel.slug)
 | 
			
		||||
            if key in loaders.panel_template_dirs:
 | 
			
		||||
                del loaders.panel_template_dirs[key]
 | 
			
		||||
        return success
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Workflow(object):
 | 
			
		||||
    def __init__(*args, **kwargs):
 | 
			
		||||
        raise NotImplementedError()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    from django.utils.functional import empty
 | 
			
		||||
except ImportError:
 | 
			
		||||
    #Django 1.3 fallback
 | 
			
		||||
    empty = None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LazyURLPattern(SimpleLazyObject):
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        if self._wrapped is empty:
 | 
			
		||||
            self._setup()
 | 
			
		||||
        return iter(self._wrapped)
 | 
			
		||||
 | 
			
		||||
    def __reversed__(self):
 | 
			
		||||
        if self._wrapped is empty:
 | 
			
		||||
            self._setup()
 | 
			
		||||
        return reversed(self._wrapped)
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        if self._wrapped is empty:
 | 
			
		||||
            self._setup()
 | 
			
		||||
        return len(self._wrapped)
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, idx):
 | 
			
		||||
        if self._wrapped is empty:
 | 
			
		||||
            self._setup()
 | 
			
		||||
        return self._wrapped[idx]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Site(Registry, HorizonComponent):
 | 
			
		||||
    """ The overarching class which encompasses all dashboards and panels. """
 | 
			
		||||
 | 
			
		||||
    # Required for registry
 | 
			
		||||
    _registerable_class = Dashboard
 | 
			
		||||
 | 
			
		||||
    name = "Horizon"
 | 
			
		||||
    namespace = 'horizon'
 | 
			
		||||
    slug = 'horizon'
 | 
			
		||||
    urls = 'horizon.site_urls'
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return u"<Site: %s>" % self.slug
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def _conf(self):
 | 
			
		||||
        return conf.HORIZON_CONFIG
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def dashboards(self):
 | 
			
		||||
        return self._conf['dashboards']
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def default_dashboard(self):
 | 
			
		||||
        return self._conf['default_dashboard']
 | 
			
		||||
 | 
			
		||||
    def register(self, dashboard):
 | 
			
		||||
        """ Registers a :class:`~horizon.Dashboard` with Horizon."""
 | 
			
		||||
        return self._register(dashboard)
 | 
			
		||||
 | 
			
		||||
    def unregister(self, dashboard):
 | 
			
		||||
        """ Unregisters a :class:`~horizon.Dashboard` from Horizon. """
 | 
			
		||||
        return self._unregister(dashboard)
 | 
			
		||||
 | 
			
		||||
    def registered(self, dashboard):
 | 
			
		||||
        return self._registered(dashboard)
 | 
			
		||||
 | 
			
		||||
    def register_panel(self, dashboard, panel):
 | 
			
		||||
        dash_instance = self.registered(dashboard)
 | 
			
		||||
        return dash_instance._register(panel)
 | 
			
		||||
 | 
			
		||||
    def unregister_panel(self, dashboard, panel):
 | 
			
		||||
        dash_instance = self.registered(dashboard)
 | 
			
		||||
        if not dash_instance:
 | 
			
		||||
            raise NotRegistered("The dashboard %s is not registered."
 | 
			
		||||
                                % dashboard)
 | 
			
		||||
        return dash_instance._unregister(panel)
 | 
			
		||||
 | 
			
		||||
    def get_dashboard(self, dashboard):
 | 
			
		||||
        """ Returns the specified :class:`~horizon.Dashboard` instance. """
 | 
			
		||||
        return self._registered(dashboard)
 | 
			
		||||
 | 
			
		||||
    def get_dashboards(self):
 | 
			
		||||
        """ Returns an ordered tuple of :class:`~horizon.Dashboard` modules.
 | 
			
		||||
 | 
			
		||||
        Orders dashboards according to the ``"dashboards"`` key in
 | 
			
		||||
        ``HORIZON_CONFIG`` or else returns all registered dashboards
 | 
			
		||||
        in alphabetical order.
 | 
			
		||||
 | 
			
		||||
        Any remaining :class:`~horizon.Dashboard` classes registered with
 | 
			
		||||
        Horizon but not listed in ``HORIZON_CONFIG['dashboards']``
 | 
			
		||||
        will be appended to the end of the list alphabetically.
 | 
			
		||||
        """
 | 
			
		||||
        if self.dashboards:
 | 
			
		||||
            registered = copy.copy(self._registry)
 | 
			
		||||
            dashboards = []
 | 
			
		||||
            for item in self.dashboards:
 | 
			
		||||
                dashboard = self._registered(item)
 | 
			
		||||
                dashboards.append(dashboard)
 | 
			
		||||
                registered.pop(dashboard.__class__)
 | 
			
		||||
            if len(registered):
 | 
			
		||||
                extra = registered.values()
 | 
			
		||||
                extra.sort()
 | 
			
		||||
                dashboards.extend(extra)
 | 
			
		||||
            return dashboards
 | 
			
		||||
        else:
 | 
			
		||||
            dashboards = self._registry.values()
 | 
			
		||||
            dashboards.sort()
 | 
			
		||||
            return dashboards
 | 
			
		||||
 | 
			
		||||
    def get_default_dashboard(self):
 | 
			
		||||
        """ Returns the default :class:`~horizon.Dashboard` instance.
 | 
			
		||||
 | 
			
		||||
        If ``"default_dashboard"`` is specified in ``HORIZON_CONFIG``
 | 
			
		||||
        then that dashboard will be returned. If not, the first dashboard
 | 
			
		||||
        returned by :func:`~horizon.get_dashboards` will be returned.
 | 
			
		||||
        """
 | 
			
		||||
        if self.default_dashboard:
 | 
			
		||||
            return self._registered(self.default_dashboard)
 | 
			
		||||
        elif len(self._registry):
 | 
			
		||||
            return self.get_dashboards()[0]
 | 
			
		||||
        else:
 | 
			
		||||
            raise NotRegistered("No dashboard modules have been registered.")
 | 
			
		||||
 | 
			
		||||
    def get_user_home(self, user):
 | 
			
		||||
        """ Returns the default URL for a particular user.
 | 
			
		||||
 | 
			
		||||
        This method can be used to customize where a user is sent when
 | 
			
		||||
        they log in, etc. By default it returns the value of
 | 
			
		||||
        :meth:`get_absolute_url`.
 | 
			
		||||
 | 
			
		||||
        An alternative function can be supplied to customize this behavior
 | 
			
		||||
        by specifying a either a URL or a function which returns a URL via
 | 
			
		||||
        the ``"user_home"`` key in ``HORIZON_CONFIG``. Each of these
 | 
			
		||||
        would be valid::
 | 
			
		||||
 | 
			
		||||
            {"user_home": "/home",}  # A URL
 | 
			
		||||
            {"user_home": "my_module.get_user_home",}  # Path to a function
 | 
			
		||||
            {"user_home": lambda user: "/" + user.name,}  # A function
 | 
			
		||||
            {"user_home": None,}  # Will always return the default dashboard
 | 
			
		||||
 | 
			
		||||
        This can be useful if the default dashboard may not be accessible
 | 
			
		||||
        to all users. When user_home is missing from HORIZON_CONFIG,
 | 
			
		||||
        it will default to the settings.LOGIN_REDIRECT_URL value.
 | 
			
		||||
        """
 | 
			
		||||
        user_home = self._conf['user_home']
 | 
			
		||||
        if user_home:
 | 
			
		||||
            if callable(user_home):
 | 
			
		||||
                return user_home(user)
 | 
			
		||||
            elif isinstance(user_home, basestring):
 | 
			
		||||
                # Assume we've got a URL if there's a slash in it
 | 
			
		||||
                if user_home.find("/") != -1:
 | 
			
		||||
                    return user_home
 | 
			
		||||
                else:
 | 
			
		||||
                    mod, func = user_home.rsplit(".", 1)
 | 
			
		||||
                    return getattr(import_module(mod), func)(user)
 | 
			
		||||
            # If it's not callable and not a string, it's wrong.
 | 
			
		||||
            raise ValueError('The user_home setting must be either a string '
 | 
			
		||||
                             'or a callable object (e.g. a function).')
 | 
			
		||||
        else:
 | 
			
		||||
            return self.get_absolute_url()
 | 
			
		||||
 | 
			
		||||
    def get_absolute_url(self):
 | 
			
		||||
        """ Returns the default URL for Horizon's URLconf.
 | 
			
		||||
 | 
			
		||||
        The default URL is determined by calling
 | 
			
		||||
        :meth:`~horizon.Dashboard.get_absolute_url`
 | 
			
		||||
        on the :class:`~horizon.Dashboard` instance returned by
 | 
			
		||||
        :meth:`~horizon.get_default_dashboard`.
 | 
			
		||||
        """
 | 
			
		||||
        return self.get_default_dashboard().get_absolute_url()
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def _lazy_urls(self):
 | 
			
		||||
        """ Lazy loading for URL patterns.
 | 
			
		||||
 | 
			
		||||
        This method avoids problems associated with attempting to evaluate
 | 
			
		||||
        the the URLconf before the settings module has been loaded.
 | 
			
		||||
        """
 | 
			
		||||
        def url_patterns():
 | 
			
		||||
            return self._urls()[0]
 | 
			
		||||
 | 
			
		||||
        return LazyURLPattern(url_patterns), self.namespace, self.slug
 | 
			
		||||
 | 
			
		||||
    def _urls(self):
 | 
			
		||||
        """ Constructs the URLconf for Horizon from registered Dashboards. """
 | 
			
		||||
        urlpatterns = self._get_default_urlpatterns()
 | 
			
		||||
        self._autodiscover()
 | 
			
		||||
 | 
			
		||||
        # Discover each dashboard's panels.
 | 
			
		||||
        for dash in self._registry.values():
 | 
			
		||||
            dash._autodiscover()
 | 
			
		||||
 | 
			
		||||
        # Allow for override modules
 | 
			
		||||
        if self._conf.get("customization_module", None):
 | 
			
		||||
            customization_module = self._conf["customization_module"]
 | 
			
		||||
            bits = customization_module.split('.')
 | 
			
		||||
            mod_name = bits.pop()
 | 
			
		||||
            package = '.'.join(bits)
 | 
			
		||||
            mod = import_module(package)
 | 
			
		||||
            try:
 | 
			
		||||
                before_import_registry = copy.copy(self._registry)
 | 
			
		||||
                import_module('%s.%s' % (package, mod_name))
 | 
			
		||||
            except:
 | 
			
		||||
                self._registry = before_import_registry
 | 
			
		||||
                if module_has_submodule(mod, mod_name):
 | 
			
		||||
                    raise
 | 
			
		||||
 | 
			
		||||
        # Compile the dynamic urlconf.
 | 
			
		||||
        for dash in self._registry.values():
 | 
			
		||||
            urlpatterns += patterns('',
 | 
			
		||||
                    url(r'^%s/' % dash.slug, include(dash._decorated_urls)))
 | 
			
		||||
 | 
			
		||||
        # Return the three arguments to django.conf.urls.defaults.include
 | 
			
		||||
        return urlpatterns, self.namespace, self.slug
 | 
			
		||||
 | 
			
		||||
    def _autodiscover(self):
 | 
			
		||||
        """ Discovers modules to register from ``settings.INSTALLED_APPS``.
 | 
			
		||||
 | 
			
		||||
        This makes sure that the appropriate modules get imported to register
 | 
			
		||||
        themselves with Horizon.
 | 
			
		||||
        """
 | 
			
		||||
        if not getattr(self, '_registerable_class', None):
 | 
			
		||||
            raise ImproperlyConfigured('You must set a '
 | 
			
		||||
                                       '"_registerable_class" property '
 | 
			
		||||
                                       'in order to use autodiscovery.')
 | 
			
		||||
        # Discover both dashboards and panels, in that order
 | 
			
		||||
        for mod_name in ('dashboard', 'panel'):
 | 
			
		||||
            for app in settings.INSTALLED_APPS:
 | 
			
		||||
                mod = import_module(app)
 | 
			
		||||
                try:
 | 
			
		||||
                    before_import_registry = copy.copy(self._registry)
 | 
			
		||||
                    import_module('%s.%s' % (app, mod_name))
 | 
			
		||||
                except:
 | 
			
		||||
                    self._registry = before_import_registry
 | 
			
		||||
                    if module_has_submodule(mod, mod_name):
 | 
			
		||||
                        raise
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HorizonSite(Site):
 | 
			
		||||
    """
 | 
			
		||||
    A singleton implementation of Site such that all dealings with horizon
 | 
			
		||||
    get the same instance no matter what. There can be only one.
 | 
			
		||||
    """
 | 
			
		||||
    _instance = None
 | 
			
		||||
 | 
			
		||||
    def __new__(cls, *args, **kwargs):
 | 
			
		||||
        if not cls._instance:
 | 
			
		||||
            cls._instance = super(Site, cls).__new__(cls, *args, **kwargs)
 | 
			
		||||
        return cls._instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# The one true Horizon
 | 
			
		||||
Horizon = HorizonSite()
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
from horizon.browsers.base import ResourceBrowser
 | 
			
		||||
from horizon.browsers.views import ResourceBrowserView
 | 
			
		||||
 | 
			
		||||
assert ResourceBrowser
 | 
			
		||||
assert ResourceBrowserView
 | 
			
		||||
@@ -1,150 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
from django import template
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from horizon.browsers.breadcrumb import Breadcrumb
 | 
			
		||||
from horizon.tables import DataTable
 | 
			
		||||
from horizon.utils import html
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ResourceBrowser(html.HTMLElement):
 | 
			
		||||
    """A class which defines a browser for displaying data.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: name
 | 
			
		||||
 | 
			
		||||
        A short name or slug for the browser.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: verbose_name
 | 
			
		||||
 | 
			
		||||
        A more verbose name for the browser meant for display purposes.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: navigation_table_class
 | 
			
		||||
 | 
			
		||||
        This table displays data on the left side of the browser.
 | 
			
		||||
        Set the ``navigation_table_class`` attribute with
 | 
			
		||||
        the desired :class:`~horizon.tables.DataTable` class.
 | 
			
		||||
        This table class must set browser_table attribute in Meta to
 | 
			
		||||
        ``"navigation"``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: content_table_class
 | 
			
		||||
 | 
			
		||||
        This table displays data on the right side of the browser.
 | 
			
		||||
        Set the ``content_table_class`` attribute with
 | 
			
		||||
        the desired :class:`~horizon.tables.DataTable` class.
 | 
			
		||||
        This table class must set browser_table attribute in Meta to
 | 
			
		||||
        ``"content"``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: navigation_kwarg_name
 | 
			
		||||
 | 
			
		||||
        This attribute represents the key of the navigatable items in the
 | 
			
		||||
        kwargs property of this browser's view.
 | 
			
		||||
        Defaults to ``"navigation_kwarg"``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: content_kwarg_name
 | 
			
		||||
 | 
			
		||||
        This attribute represents the key of the content items in the
 | 
			
		||||
        kwargs property of this browser's view.
 | 
			
		||||
        Defaults to ``"content_kwarg"``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: template
 | 
			
		||||
 | 
			
		||||
        String containing the template which should be used to render
 | 
			
		||||
        the browser. Defaults to ``"horizon/common/_resource_browser.html"``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: context_var_name
 | 
			
		||||
 | 
			
		||||
        The name of the context variable which will contain the browser when
 | 
			
		||||
        it is rendered. Defaults to ``"browser"``.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: has_breadcrumb
 | 
			
		||||
 | 
			
		||||
        Indicates if the content table of the browser would have breadcrumb.
 | 
			
		||||
        Defaults to false.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: breadcrumb_template
 | 
			
		||||
 | 
			
		||||
        This is a template used to render the breadcrumb.
 | 
			
		||||
        Defaults to ``"horizon/common/_breadcrumb.html"``.
 | 
			
		||||
    """
 | 
			
		||||
    name = None
 | 
			
		||||
    verbose_name = None
 | 
			
		||||
    navigation_table_class = None
 | 
			
		||||
    content_table_class = None
 | 
			
		||||
    navigation_kwarg_name = "navigation_kwarg"
 | 
			
		||||
    content_kwarg_name = "content_kwarg"
 | 
			
		||||
    navigable_item_name = _("Navigation Item")
 | 
			
		||||
    template = "horizon/common/_resource_browser.html"
 | 
			
		||||
    context_var_name = "browser"
 | 
			
		||||
    has_breadcrumb = False
 | 
			
		||||
    breadcrumb_template = "horizon/common/_breadcrumb.html"
 | 
			
		||||
    breadcrumb_url = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, request, tables_dict=None, attrs=None, **kwargs):
 | 
			
		||||
        super(ResourceBrowser, self).__init__()
 | 
			
		||||
        self.name = self.name or self.__class__.__name__
 | 
			
		||||
        self.verbose_name = self.verbose_name or self.name.title()
 | 
			
		||||
        self.request = request
 | 
			
		||||
        self.kwargs = kwargs
 | 
			
		||||
        self.has_breadcrumb = getattr(self, "has_breadcrumb")
 | 
			
		||||
        if self.has_breadcrumb:
 | 
			
		||||
            self.breadcrumb_template = getattr(self, "breadcrumb_template")
 | 
			
		||||
            self.breadcrumb_url = getattr(self, "breadcrumb_url")
 | 
			
		||||
            if not self.breadcrumb_url:
 | 
			
		||||
                raise ValueError("You must specify a breadcrumb_url "
 | 
			
		||||
                                 "if the has_breadcrumb is set to True.")
 | 
			
		||||
        self.attrs.update(attrs or {})
 | 
			
		||||
        self.check_table_class(self.content_table_class, "content_table_class")
 | 
			
		||||
        self.check_table_class(self.navigation_table_class,
 | 
			
		||||
                               "navigation_table_class")
 | 
			
		||||
        if tables_dict:
 | 
			
		||||
            self.set_tables(tables_dict)
 | 
			
		||||
 | 
			
		||||
    def check_table_class(self, cls, attr_name):
 | 
			
		||||
        if not cls or not issubclass(cls, DataTable):
 | 
			
		||||
            raise ValueError("You must specify a DataTable subclass for "
 | 
			
		||||
                             "the %s attribute on %s."
 | 
			
		||||
                             % (attr_name, self.__class__.__name__))
 | 
			
		||||
 | 
			
		||||
    def set_tables(self, tables):
 | 
			
		||||
        """
 | 
			
		||||
        Sets the table instances on the browser from a dictionary mapping table
 | 
			
		||||
        names to table instances (as constructed by MultiTableView).
 | 
			
		||||
        """
 | 
			
		||||
        self.navigation_table = tables[self.navigation_table_class._meta.name]
 | 
			
		||||
        self.content_table = tables[self.content_table_class._meta.name]
 | 
			
		||||
        navigation_item = self.kwargs.get(self.navigation_kwarg_name)
 | 
			
		||||
        content_path = self.kwargs.get(self.content_kwarg_name)
 | 
			
		||||
        # Tells the navigation table what is selected.
 | 
			
		||||
        self.navigation_table.current_item_id = navigation_item
 | 
			
		||||
        if self.has_breadcrumb:
 | 
			
		||||
            self.prepare_breadcrumb(tables, navigation_item, content_path)
 | 
			
		||||
 | 
			
		||||
    def prepare_breadcrumb(self, tables, navigation_item, content_path):
 | 
			
		||||
        if self.has_breadcrumb and navigation_item and content_path:
 | 
			
		||||
            for table in tables.values():
 | 
			
		||||
                table.breadcrumb = Breadcrumb(self.request,
 | 
			
		||||
                                              self.breadcrumb_template,
 | 
			
		||||
                                              navigation_item,
 | 
			
		||||
                                              content_path,
 | 
			
		||||
                                              self.breadcrumb_url)
 | 
			
		||||
 | 
			
		||||
    def render(self):
 | 
			
		||||
        browser_template = template.loader.get_template(self.template)
 | 
			
		||||
        extra_context = {self.context_var_name: self}
 | 
			
		||||
        context = template.RequestContext(self.request, extra_context)
 | 
			
		||||
        return browser_template.render(context)
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
from django import template
 | 
			
		||||
 | 
			
		||||
from horizon.utils import html
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Breadcrumb(html.HTMLElement):
 | 
			
		||||
    def __init__(self, request, template, root,
 | 
			
		||||
                 subfolder_path, url, attr=None):
 | 
			
		||||
        super(Breadcrumb, self).__init__()
 | 
			
		||||
        self.template = template
 | 
			
		||||
        self.request = request
 | 
			
		||||
        self.root = root
 | 
			
		||||
        self.subfolder_path = subfolder_path
 | 
			
		||||
        self.url = url
 | 
			
		||||
        self._subfolders = []
 | 
			
		||||
 | 
			
		||||
    def get_subfolders(self):
 | 
			
		||||
        if self.subfolder_path and not self._subfolders:
 | 
			
		||||
            (parent, slash, folder) = self.subfolder_path.strip('/') \
 | 
			
		||||
                                                        .rpartition('/')
 | 
			
		||||
            while folder:
 | 
			
		||||
                path = "%s%s%s/" % (parent, slash, folder)
 | 
			
		||||
                self._subfolders.insert(0, (folder, path))
 | 
			
		||||
                (parent, slash, folder) = parent.rpartition('/')
 | 
			
		||||
        return self._subfolders
 | 
			
		||||
 | 
			
		||||
    def render(self):
 | 
			
		||||
        """ Renders the table using the template from the table options. """
 | 
			
		||||
        breadcrumb_template = template.loader.get_template(self.template)
 | 
			
		||||
        extra_context = {"breadcrumb": self}
 | 
			
		||||
        context = template.RequestContext(self.request, extra_context)
 | 
			
		||||
        return breadcrumb_template.render(context)
 | 
			
		||||
@@ -1,49 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from horizon.tables import MultiTableView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ResourceBrowserView(MultiTableView):
 | 
			
		||||
    browser_class = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        if not self.browser_class:
 | 
			
		||||
            raise ValueError("You must specify a ResourceBrowser subclass "
 | 
			
		||||
                             "for the browser_class attribute on %s."
 | 
			
		||||
                             % self.__class__.__name__)
 | 
			
		||||
        self.table_classes = (self.browser_class.navigation_table_class,
 | 
			
		||||
                              self.browser_class.content_table_class)
 | 
			
		||||
        self.navigation_selection = False
 | 
			
		||||
        super(ResourceBrowserView, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_browser(self):
 | 
			
		||||
        if not hasattr(self, "browser"):
 | 
			
		||||
            self.browser = self.browser_class(self.request, **self.kwargs)
 | 
			
		||||
            self.browser.set_tables(self.get_tables())
 | 
			
		||||
            if not self.navigation_selection:
 | 
			
		||||
                ct = self.browser.content_table
 | 
			
		||||
                item = self.browser.navigable_item_name.lower()
 | 
			
		||||
                ct._no_data_message = _("Select a %s to browse.") % item
 | 
			
		||||
        return self.browser
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super(ResourceBrowserView, self).get_context_data(**kwargs)
 | 
			
		||||
        browser = self.get_browser()
 | 
			
		||||
        context["%s_browser" % browser.name] = browser
 | 
			
		||||
        return context
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
import copy
 | 
			
		||||
 | 
			
		||||
from django.utils.functional import empty
 | 
			
		||||
from django.utils.functional import LazyObject
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LazySettings(LazyObject):
 | 
			
		||||
    def _setup(self, name=None):
 | 
			
		||||
        from django.conf import settings
 | 
			
		||||
        from horizon.conf.default import HORIZON_CONFIG as DEFAULT_CONFIG
 | 
			
		||||
        HORIZON_CONFIG = copy.copy(DEFAULT_CONFIG)
 | 
			
		||||
        HORIZON_CONFIG.update(settings.HORIZON_CONFIG)
 | 
			
		||||
 | 
			
		||||
        # Ensure we always have our exception configuration...
 | 
			
		||||
        for exc_category in ['unauthorized', 'not_found', 'recoverable']:
 | 
			
		||||
            if exc_category not in HORIZON_CONFIG['exceptions']:
 | 
			
		||||
                default_exc_config = DEFAULT_CONFIG['exceptions'][exc_category]
 | 
			
		||||
                HORIZON_CONFIG['exceptions'][exc_category] = default_exc_config
 | 
			
		||||
 | 
			
		||||
        # Ensure our password validator always exists...
 | 
			
		||||
        if 'regex' not in HORIZON_CONFIG['password_validator']:
 | 
			
		||||
            default_pw_regex = DEFAULT_CONFIG['password_validator']['regex']
 | 
			
		||||
            HORIZON_CONFIG['password_validator']['regex'] = default_pw_regex
 | 
			
		||||
        if 'help_text' not in HORIZON_CONFIG['password_validator']:
 | 
			
		||||
            default_pw_help = DEFAULT_CONFIG['password_validator']['help_text']
 | 
			
		||||
            HORIZON_CONFIG['password_validator']['help_text'] = default_pw_help
 | 
			
		||||
 | 
			
		||||
        self._wrapped = HORIZON_CONFIG
 | 
			
		||||
 | 
			
		||||
    def __getitem__(self, name, fallback=None):
 | 
			
		||||
        if self._wrapped is empty:
 | 
			
		||||
            self._setup(name)
 | 
			
		||||
        return self._wrapped.get(name, fallback)
 | 
			
		||||
 | 
			
		||||
HORIZON_CONFIG = LazySettings()
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
import horizon
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class {{ dash_name|title }}(horizon.Dashboard):
 | 
			
		||||
    name = _("{{ dash_name|title }}")
 | 
			
		||||
    slug = "{{ dash_name|slugify }}"
 | 
			
		||||
    panels = ()  # Add your panels here.
 | 
			
		||||
    default_panel = ''  # Specify the slug of the dashboard's default panel.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
horizon.register({{ dash_name|title }})
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
 | 
			
		||||
"""
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
/* Additional CSS for {{ dash_name }}. */
 | 
			
		||||
@@ -1 +0,0 @@
 | 
			
		||||
/* Additional JavaScript for {{ dash_name }}. */
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
{% load horizon %}{% jstemplate %}[% extends 'base.html' %]
 | 
			
		||||
 | 
			
		||||
[% block sidebar %]
 | 
			
		||||
  [% include 'horizon/common/_sidebar.html' %]
 | 
			
		||||
[% endblock %]
 | 
			
		||||
 | 
			
		||||
[% block main %]
 | 
			
		||||
    [% include "horizon/_messages.html" %]
 | 
			
		||||
    [% block {{ dash_name }}_main %][% endblock %]
 | 
			
		||||
[% endblock %]
 | 
			
		||||
{% endjstemplate %}
 | 
			
		||||
@@ -1,35 +0,0 @@
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
# Default configuration dictionary. Do not mutate.
 | 
			
		||||
HORIZON_CONFIG = {
 | 
			
		||||
    # Allow for ordering dashboards; list or tuple if provided.
 | 
			
		||||
    'dashboards': None,
 | 
			
		||||
 | 
			
		||||
    # Name of a default dashboard; defaults to first alphabetically if None
 | 
			
		||||
    'default_dashboard': None,
 | 
			
		||||
 | 
			
		||||
    # Default redirect url for users' home
 | 
			
		||||
    'user_home': settings.LOGIN_REDIRECT_URL,
 | 
			
		||||
 | 
			
		||||
    # AJAX settings for JavaScript
 | 
			
		||||
    'ajax_queue_limit': 10,
 | 
			
		||||
    'ajax_poll_interval': 2500,
 | 
			
		||||
 | 
			
		||||
    # URL for additional help with this site.
 | 
			
		||||
    'help_url': None,
 | 
			
		||||
 | 
			
		||||
    # Exception configuration.
 | 
			
		||||
    'exceptions': {'unauthorized': [],
 | 
			
		||||
                   'not_found': [],
 | 
			
		||||
                   'recoverable': []},
 | 
			
		||||
 | 
			
		||||
    # Password configuration.
 | 
			
		||||
    'password_validator': {'regex': '.*',
 | 
			
		||||
                           'help_text': _("Password is not accepted")},
 | 
			
		||||
 | 
			
		||||
    'password_autocomplete': 'on',
 | 
			
		||||
 | 
			
		||||
    # Enable or disable simplified floating IP address management.
 | 
			
		||||
    'simple_ip_management': True
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
 | 
			
		||||
"""
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
import horizon
 | 
			
		||||
 | 
			
		||||
from {{ dash_path }} import dashboard
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class {{ panel_name|title }}(horizon.Panel):
 | 
			
		||||
    name = _("{{ panel_name|title }}")
 | 
			
		||||
    slug = "{{ panel_name|slugify }}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
dashboard.{{ dash_name|title }}.register({{ panel_name|title }})
 | 
			
		||||
@@ -1,12 +0,0 @@
 | 
			
		||||
{% load horizon %}{% jstemplate %}[% extends '{{ dash_name }}/base.html' %]
 | 
			
		||||
[% load i18n %]
 | 
			
		||||
[% block title %][% trans "{{ panel_name|title }}" %][% endblock %]
 | 
			
		||||
 | 
			
		||||
[% block page_header %]
 | 
			
		||||
  [% include "horizon/common/_page_header.html" with title=_("{{ panel_name|title }}") %]
 | 
			
		||||
[% endblock page_header %]
 | 
			
		||||
 | 
			
		||||
[% block {{ dash_name }}_main %]
 | 
			
		||||
[% endblock %]
 | 
			
		||||
 | 
			
		||||
{% endjstemplate %}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
from horizon.test import helpers as test
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class {{ panel_name|title}}Tests(test.TestCase):
 | 
			
		||||
    # Unit tests for {{ panel_name }}.
 | 
			
		||||
    def test_me(self):
 | 
			
		||||
        self.assertTrue(1 + 1 == 2)
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
from django.conf.urls.defaults import patterns, url
 | 
			
		||||
 | 
			
		||||
from .views import IndexView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
urlpatterns = patterns('',
 | 
			
		||||
    url(r'^$', IndexView.as_view(), name='index'),
 | 
			
		||||
)
 | 
			
		||||
@@ -1,10 +0,0 @@
 | 
			
		||||
from horizon import views
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IndexView(views.APIView):
 | 
			
		||||
    # A very simple class-based view...
 | 
			
		||||
    template_name = '{{ dash_name }}/{{ panel_name }}/index.html'
 | 
			
		||||
 | 
			
		||||
    def get_data(self, request, context, *args, **kwargs):
 | 
			
		||||
        # Add data to the context here...
 | 
			
		||||
        return context
 | 
			
		||||
@@ -1,44 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 United States Government as represented by the
 | 
			
		||||
# Administrator of the National Aeronautics and Space Administration.
 | 
			
		||||
# All Rights Reserved.
 | 
			
		||||
#
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
"""
 | 
			
		||||
Context processors used by Horizon.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from horizon import conf
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def horizon(request):
 | 
			
		||||
    """ The main Horizon context processor. Required for Horizon to function.
 | 
			
		||||
 | 
			
		||||
    It adds the Horizon config to the context as well as setting the names
 | 
			
		||||
    ``True`` and ``False`` in the context to their boolean equivalents
 | 
			
		||||
    for convenience.
 | 
			
		||||
 | 
			
		||||
    .. warning::
 | 
			
		||||
 | 
			
		||||
        Don't put API calls in context processors; they will be called once
 | 
			
		||||
        for each template/template fragment which takes context that is used
 | 
			
		||||
        to render the complete output.
 | 
			
		||||
    """
 | 
			
		||||
    context = {"HORIZON_CONFIG": conf.HORIZON_CONFIG,
 | 
			
		||||
               "True": True,
 | 
			
		||||
               "False": False}
 | 
			
		||||
 | 
			
		||||
    return context
 | 
			
		||||
@@ -1,94 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 United States Government as represented by the
 | 
			
		||||
# Administrator of the National Aeronautics and Space Administration.
 | 
			
		||||
# All Rights Reserved.
 | 
			
		||||
#
 | 
			
		||||
# Copyright 2012 CRS4
 | 
			
		||||
#
 | 
			
		||||
#    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.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
General-purpose decorators for use with Horizon.
 | 
			
		||||
"""
 | 
			
		||||
import functools
 | 
			
		||||
 | 
			
		||||
from django.utils.decorators import available_attrs
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _current_component(view_func, dashboard=None, panel=None):
 | 
			
		||||
    """ Sets the currently-active dashboard and/or panel on the request. """
 | 
			
		||||
    @functools.wraps(view_func, assigned=available_attrs(view_func))
 | 
			
		||||
    def dec(request, *args, **kwargs):
 | 
			
		||||
        if dashboard:
 | 
			
		||||
            request.horizon['dashboard'] = dashboard
 | 
			
		||||
        if panel:
 | 
			
		||||
            request.horizon['panel'] = panel
 | 
			
		||||
        return view_func(request, *args, **kwargs)
 | 
			
		||||
    return dec
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def require_auth(view_func):
 | 
			
		||||
    """ Performs user authentication check.
 | 
			
		||||
 | 
			
		||||
    Similar to Django's `login_required` decorator, except that this throws
 | 
			
		||||
    :exc:`~horizon.exceptions.NotAuthenticated` exception if the user is not
 | 
			
		||||
    signed-in.
 | 
			
		||||
    """
 | 
			
		||||
    from horizon.exceptions import NotAuthenticated
 | 
			
		||||
 | 
			
		||||
    @functools.wraps(view_func, assigned=available_attrs(view_func))
 | 
			
		||||
    def dec(request, *args, **kwargs):
 | 
			
		||||
        if request.user.is_authenticated():
 | 
			
		||||
            return view_func(request, *args, **kwargs)
 | 
			
		||||
        raise NotAuthenticated(_("Please log in to continue."))
 | 
			
		||||
    return dec
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def require_perms(view_func, required):
 | 
			
		||||
    """ Enforces permission-based access controls.
 | 
			
		||||
 | 
			
		||||
    :param list required: A tuple of permission names, all of which the request
 | 
			
		||||
                          user must possess in order access the decorated view.
 | 
			
		||||
 | 
			
		||||
    Example usage::
 | 
			
		||||
 | 
			
		||||
        from horizon.decorators import require_perms
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        @require_perms(['foo.admin', 'foo.member'])
 | 
			
		||||
        def my_view(request):
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
    Raises a :exc:`~horizon.exceptions.NotAuthorized` exception if the
 | 
			
		||||
    requirements are not met.
 | 
			
		||||
    """
 | 
			
		||||
    from horizon.exceptions import NotAuthorized
 | 
			
		||||
    # We only need to check each permission once for a view, so we'll use a set
 | 
			
		||||
    current_perms = getattr(view_func, '_required_perms', set([]))
 | 
			
		||||
    view_func._required_perms = current_perms | set(required)
 | 
			
		||||
 | 
			
		||||
    @functools.wraps(view_func, assigned=available_attrs(view_func))
 | 
			
		||||
    def dec(request, *args, **kwargs):
 | 
			
		||||
        if request.user.is_authenticated():
 | 
			
		||||
            if request.user.has_perms(view_func._required_perms):
 | 
			
		||||
                return view_func(request, *args, **kwargs)
 | 
			
		||||
        raise NotAuthorized(_("You are not authorized to access %s")
 | 
			
		||||
                            % request.path)
 | 
			
		||||
 | 
			
		||||
    # If we don't have any permissions, just return the original view.
 | 
			
		||||
    if required:
 | 
			
		||||
        return dec
 | 
			
		||||
    else:
 | 
			
		||||
        return view_func
 | 
			
		||||
@@ -1,321 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
Exceptions raised by the Horizon code and the machinery for handling them.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth import logout
 | 
			
		||||
from django.core.management import color_style
 | 
			
		||||
from django.http import HttpRequest
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
from django.views.debug import CLEANSED_SUBSTITUTE
 | 
			
		||||
from django.views.debug import SafeExceptionReporterFilter
 | 
			
		||||
 | 
			
		||||
from horizon.conf import HORIZON_CONFIG
 | 
			
		||||
from horizon import messages
 | 
			
		||||
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HorizonReporterFilter(SafeExceptionReporterFilter):
 | 
			
		||||
    """ Error report filter that's always active, even in DEBUG mode. """
 | 
			
		||||
    def is_active(self, request):
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    # TODO(gabriel): This bugfix is cribbed from Django's code. When 1.4.1
 | 
			
		||||
    # is available we can remove this code.
 | 
			
		||||
    def get_traceback_frame_variables(self, request, tb_frame):
 | 
			
		||||
        """
 | 
			
		||||
        Replaces the values of variables marked as sensitive with
 | 
			
		||||
        stars (*********).
 | 
			
		||||
        """
 | 
			
		||||
        # Loop through the frame's callers to see if the sensitive_variables
 | 
			
		||||
        # decorator was used.
 | 
			
		||||
        current_frame = tb_frame.f_back
 | 
			
		||||
        sensitive_variables = None
 | 
			
		||||
        while current_frame is not None:
 | 
			
		||||
            if (current_frame.f_code.co_name == 'sensitive_variables_wrapper'
 | 
			
		||||
                    and 'sensitive_variables_wrapper'
 | 
			
		||||
                    in current_frame.f_locals):
 | 
			
		||||
                # The sensitive_variables decorator was used, so we take note
 | 
			
		||||
                # of the sensitive variables' names.
 | 
			
		||||
                wrapper = current_frame.f_locals['sensitive_variables_wrapper']
 | 
			
		||||
                sensitive_variables = getattr(wrapper,
 | 
			
		||||
                                              'sensitive_variables',
 | 
			
		||||
                                              None)
 | 
			
		||||
                break
 | 
			
		||||
            current_frame = current_frame.f_back
 | 
			
		||||
 | 
			
		||||
        cleansed = []
 | 
			
		||||
        if self.is_active(request) and sensitive_variables:
 | 
			
		||||
            if sensitive_variables == '__ALL__':
 | 
			
		||||
                # Cleanse all variables
 | 
			
		||||
                for name, value in tb_frame.f_locals.items():
 | 
			
		||||
                    cleansed.append((name, CLEANSED_SUBSTITUTE))
 | 
			
		||||
                return cleansed
 | 
			
		||||
            else:
 | 
			
		||||
                # Cleanse specified variables
 | 
			
		||||
                for name, value in tb_frame.f_locals.items():
 | 
			
		||||
                    if name in sensitive_variables:
 | 
			
		||||
                        value = CLEANSED_SUBSTITUTE
 | 
			
		||||
                    elif isinstance(value, HttpRequest):
 | 
			
		||||
                        # Cleanse the request's POST parameters.
 | 
			
		||||
                        value = self.get_request_repr(value)
 | 
			
		||||
                    cleansed.append((name, value))
 | 
			
		||||
                return cleansed
 | 
			
		||||
        else:
 | 
			
		||||
            # Potentially cleanse only the request if it's one of the
 | 
			
		||||
            # frame variables.
 | 
			
		||||
            for name, value in tb_frame.f_locals.items():
 | 
			
		||||
                if isinstance(value, HttpRequest):
 | 
			
		||||
                    # Cleanse the request's POST parameters.
 | 
			
		||||
                    value = self.get_request_repr(value)
 | 
			
		||||
                cleansed.append((name, value))
 | 
			
		||||
            return cleansed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HorizonException(Exception):
 | 
			
		||||
    """ Base exception class for distinguishing our own exception classes. """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Http302(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Error class which can be raised from within a handler to cause an
 | 
			
		||||
    early bailout and redirect at the middleware level.
 | 
			
		||||
    """
 | 
			
		||||
    status_code = 302
 | 
			
		||||
 | 
			
		||||
    def __init__(self, location, message=None):
 | 
			
		||||
        self.location = location
 | 
			
		||||
        self.message = message
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NotAuthorized(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Raised whenever a user attempts to access a resource which they do not
 | 
			
		||||
    have permission-based access to (such as when failing the
 | 
			
		||||
    :func:`~horizon.decorators.require_perms` decorator).
 | 
			
		||||
 | 
			
		||||
    The included :class:`~horizon.middleware.HorizonMiddleware` catches
 | 
			
		||||
    ``NotAuthorized`` and handles it gracefully by displaying an error
 | 
			
		||||
    message and redirecting the user to a login page.
 | 
			
		||||
    """
 | 
			
		||||
    status_code = 401
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NotAuthenticated(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Raised when a user is trying to make requests and they are not logged in.
 | 
			
		||||
 | 
			
		||||
    The included :class:`~horizon.middleware.HorizonMiddleware` catches
 | 
			
		||||
    ``NotAuthenticated`` and handles it gracefully by displaying an error
 | 
			
		||||
    message and redirecting the user to a login page.
 | 
			
		||||
    """
 | 
			
		||||
    status_code = 403
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NotFound(HorizonException):
 | 
			
		||||
    """ Generic error to replace all "Not Found"-type API errors. """
 | 
			
		||||
    status_code = 404
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RecoverableError(HorizonException):
 | 
			
		||||
    """ Generic error to replace any "Recoverable"-type API errors. """
 | 
			
		||||
    status_code = 100  # HTTP status code "Continue"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServiceCatalogException(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Raised when a requested service is not available in the ``ServiceCatalog``
 | 
			
		||||
    returned by Keystone.
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, service_name):
 | 
			
		||||
        message = 'Invalid service catalog service: %s' % service_name
 | 
			
		||||
        super(ServiceCatalogException, self).__init__(message)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AlreadyExists(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Exception to be raised when trying to create an API resource which
 | 
			
		||||
    already exists.
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, name, resource_type):
 | 
			
		||||
        self.attrs = {"name": name, "resource": resource_type}
 | 
			
		||||
        self.msg = 'A %(resource)s with the name "%(name)s" already exists.'
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return self.msg % self.attrs
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.msg % self.attrs
 | 
			
		||||
 | 
			
		||||
    def __unicode__(self):
 | 
			
		||||
        return _(self.msg) % self.attrs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class WorkflowError(HorizonException):
 | 
			
		||||
    """ Exception to be raised when something goes wrong in a workflow. """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class WorkflowValidationError(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Exception raised during workflow validation if required data is missing,
 | 
			
		||||
    or existing data is not valid.
 | 
			
		||||
    """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HandledException(HorizonException):
 | 
			
		||||
    """
 | 
			
		||||
    Used internally to track exceptions that have gone through
 | 
			
		||||
    :func:`horizon.exceptions.handle` more than once.
 | 
			
		||||
    """
 | 
			
		||||
    def __init__(self, wrapped):
 | 
			
		||||
        self.wrapped = wrapped
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
UNAUTHORIZED = tuple(HORIZON_CONFIG['exceptions']['unauthorized'])
 | 
			
		||||
NOT_FOUND = tuple(HORIZON_CONFIG['exceptions']['not_found'])
 | 
			
		||||
RECOVERABLE = (AlreadyExists,)
 | 
			
		||||
RECOVERABLE += tuple(HORIZON_CONFIG['exceptions']['recoverable'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def error_color(msg):
 | 
			
		||||
    return color_style().ERROR_OUTPUT(msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def check_message(keywords, message):
 | 
			
		||||
    """
 | 
			
		||||
    Checks an exception for given keywords and raises a new ``ActionError``
 | 
			
		||||
    with the desired message if the keywords are found. This allows selective
 | 
			
		||||
    control over API error messages.
 | 
			
		||||
    """
 | 
			
		||||
    exc_type, exc_value, exc_traceback = sys.exc_info()
 | 
			
		||||
    if set(str(exc_value).split(" ")).issuperset(set(keywords)):
 | 
			
		||||
        exc_value._safe_message = message
 | 
			
		||||
        raise
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def handle(request, message=None, redirect=None, ignore=False,
 | 
			
		||||
           escalate=False, log_level=None, force_log=None):
 | 
			
		||||
    """ Centralized error handling for Horizon.
 | 
			
		||||
 | 
			
		||||
    Because Horizon consumes so many different APIs with completely
 | 
			
		||||
    different ``Exception`` types, it's necessary to have a centralized
 | 
			
		||||
    place for handling exceptions which may be raised.
 | 
			
		||||
 | 
			
		||||
    Exceptions are roughly divided into 3 types:
 | 
			
		||||
 | 
			
		||||
    #. ``UNAUTHORIZED``: Errors resulting from authentication or authorization
 | 
			
		||||
       problems. These result in being logged out and sent to the login screen.
 | 
			
		||||
    #. ``NOT_FOUND``: Errors resulting from objects which could not be
 | 
			
		||||
       located via the API. These generally result in a user-facing error
 | 
			
		||||
       message, but are otherwise returned to the normal code flow. Optionally
 | 
			
		||||
       a redirect value may be passed to the error handler so users are
 | 
			
		||||
       returned to a different view than the one requested in addition to the
 | 
			
		||||
       error message.
 | 
			
		||||
    #. RECOVERABLE: Generic API errors which generate a user-facing message
 | 
			
		||||
       but drop directly back to the regular code flow.
 | 
			
		||||
 | 
			
		||||
    All other exceptions bubble the stack as normal unless the ``ignore``
 | 
			
		||||
    argument is passed in as ``True``, in which case only unrecognized
 | 
			
		||||
    errors are bubbled.
 | 
			
		||||
 | 
			
		||||
    If the exception is not re-raised, an appropriate wrapper exception
 | 
			
		||||
    class indicating the type of exception that was encountered will be
 | 
			
		||||
    returned.
 | 
			
		||||
    """
 | 
			
		||||
    exc_type, exc_value, exc_traceback = sys.exc_info()
 | 
			
		||||
    log_method = getattr(LOG, log_level or "exception")
 | 
			
		||||
    force_log = force_log or os.environ.get("HORIZON_TEST_RUN", False)
 | 
			
		||||
    force_silence = getattr(exc_value, "silence_logging", False)
 | 
			
		||||
 | 
			
		||||
    # Because the same exception may travel through this method more than
 | 
			
		||||
    # once (if it's re-raised) we may want to treat it differently
 | 
			
		||||
    # the second time (e.g. no user messages/logging).
 | 
			
		||||
    handled = issubclass(exc_type, HandledException)
 | 
			
		||||
    wrap = False
 | 
			
		||||
 | 
			
		||||
    # Restore our original exception information, but re-wrap it at the end
 | 
			
		||||
    if handled:
 | 
			
		||||
        exc_type, exc_value, exc_traceback = exc_value.wrapped
 | 
			
		||||
        wrap = True
 | 
			
		||||
 | 
			
		||||
    # We trust messages from our own exceptions
 | 
			
		||||
    if issubclass(exc_type, HorizonException):
 | 
			
		||||
        message = exc_value
 | 
			
		||||
    # Check for an override message
 | 
			
		||||
    elif getattr(exc_value, "_safe_message", None):
 | 
			
		||||
        message = exc_value._safe_message
 | 
			
		||||
    # If the message has a placeholder for the exception, fill it in
 | 
			
		||||
    elif message and "%(exc)s" in message:
 | 
			
		||||
        message = message % {"exc": exc_value}
 | 
			
		||||
 | 
			
		||||
    if issubclass(exc_type, UNAUTHORIZED):
 | 
			
		||||
        if ignore:
 | 
			
		||||
            return NotAuthorized
 | 
			
		||||
        if not force_silence and not handled:
 | 
			
		||||
            log_method(error_color("Unauthorized: %s" % exc_value))
 | 
			
		||||
        if not handled:
 | 
			
		||||
            if message:
 | 
			
		||||
                message = _("Unauthorized: %s") % message
 | 
			
		||||
            # We get some pretty useless error messages back from
 | 
			
		||||
            # some clients, so let's define our own fallback.
 | 
			
		||||
            fallback = _("Unauthorized. Please try logging in again.")
 | 
			
		||||
            messages.error(request, message or fallback)
 | 
			
		||||
        # Escalation means logging the user out and raising NotAuthorized
 | 
			
		||||
        # so the middleware will redirect them appropriately.
 | 
			
		||||
        if escalate:
 | 
			
		||||
            logout(request)
 | 
			
		||||
            raise NotAuthorized
 | 
			
		||||
        # Otherwise continue and present our "unauthorized" error message.
 | 
			
		||||
        return NotAuthorized
 | 
			
		||||
 | 
			
		||||
    if issubclass(exc_type, NOT_FOUND):
 | 
			
		||||
        wrap = True
 | 
			
		||||
        if not force_silence and not handled and (not ignore or force_log):
 | 
			
		||||
            log_method(error_color("Not Found: %s" % exc_value))
 | 
			
		||||
        if not ignore and not handled:
 | 
			
		||||
            messages.error(request, message or exc_value)
 | 
			
		||||
        if redirect:
 | 
			
		||||
            raise Http302(redirect)
 | 
			
		||||
        if not escalate:
 | 
			
		||||
            return NotFound  # return to normal code flow
 | 
			
		||||
 | 
			
		||||
    if issubclass(exc_type, RECOVERABLE):
 | 
			
		||||
        wrap = True
 | 
			
		||||
        if not force_silence and not handled and (not ignore or force_log):
 | 
			
		||||
            # Default recoverable error to WARN log level
 | 
			
		||||
            log_method = getattr(LOG, log_level or "warning")
 | 
			
		||||
            log_method(error_color("Recoverable error: %s" % exc_value))
 | 
			
		||||
        if not ignore and not handled:
 | 
			
		||||
            messages.error(request, message or exc_value)
 | 
			
		||||
        if redirect:
 | 
			
		||||
            raise Http302(redirect)
 | 
			
		||||
        if not escalate:
 | 
			
		||||
            return RecoverableError  # return to normal code flow
 | 
			
		||||
 | 
			
		||||
    # If we've gotten here, time to wrap and/or raise our exception.
 | 
			
		||||
    if wrap:
 | 
			
		||||
        raise HandledException([exc_type, exc_value, exc_traceback])
 | 
			
		||||
    raise exc_type, exc_value, exc_traceback
 | 
			
		||||
@@ -1,40 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
# FIXME(gabriel): Legacy imports for API compatibility.
 | 
			
		||||
from django.forms import *  # noqa
 | 
			
		||||
from django.forms import widgets
 | 
			
		||||
 | 
			
		||||
# Convenience imports for public API components.
 | 
			
		||||
from horizon.forms.base import DateForm
 | 
			
		||||
from horizon.forms.base import SelfHandlingForm
 | 
			
		||||
from horizon.forms.base import SelfHandlingMixin
 | 
			
		||||
from horizon.forms.fields import DynamicChoiceField
 | 
			
		||||
from horizon.forms.fields import DynamicTypedChoiceField
 | 
			
		||||
# FIXME: TableStep hack adding NumberInput
 | 
			
		||||
from horizon.forms.fields import NumberInput
 | 
			
		||||
from horizon.forms.views import ModalFormMixin
 | 
			
		||||
from horizon.forms.views import ModalFormView
 | 
			
		||||
 | 
			
		||||
assert widgets
 | 
			
		||||
assert SelfHandlingMixin
 | 
			
		||||
assert SelfHandlingForm
 | 
			
		||||
assert DateForm
 | 
			
		||||
assert ModalFormView
 | 
			
		||||
assert ModalFormMixin
 | 
			
		||||
assert DynamicTypedChoiceField
 | 
			
		||||
assert DynamicChoiceField
 | 
			
		||||
assert NumberInput
 | 
			
		||||
@@ -1,57 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 United States Government as represented by the
 | 
			
		||||
# Administrator of the National Aeronautics and Space Administration.
 | 
			
		||||
# All Rights Reserved.
 | 
			
		||||
#
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.forms.forms import NON_FIELD_ERRORS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SelfHandlingMixin(object):
 | 
			
		||||
    def __init__(self, request, *args, **kwargs):
 | 
			
		||||
        self.request = request
 | 
			
		||||
        if not hasattr(self, "handle"):
 | 
			
		||||
            raise NotImplementedError("%s does not define a handle method."
 | 
			
		||||
                                      % self.__class__.__name__)
 | 
			
		||||
        super(SelfHandlingMixin, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SelfHandlingForm(SelfHandlingMixin, forms.Form):
 | 
			
		||||
    """
 | 
			
		||||
    A base :class:`Form <django:django.forms.Form>` class which includes
 | 
			
		||||
    processing logic in its subclasses.
 | 
			
		||||
    """
 | 
			
		||||
    def api_error(self, message):
 | 
			
		||||
        """
 | 
			
		||||
        Adds an error to the form's error dictionary after validation
 | 
			
		||||
        based on problems reported via the API. This is useful when you
 | 
			
		||||
        wish for API errors to appear as errors on the form rather than
 | 
			
		||||
        using the messages framework.
 | 
			
		||||
        """
 | 
			
		||||
        self._errors[NON_FIELD_ERRORS] = self.error_class([message])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DateForm(forms.Form):
 | 
			
		||||
    """ A simple form for selecting a range of time. """
 | 
			
		||||
    start = forms.DateField(input_formats=("%Y-%m-%d",))
 | 
			
		||||
    end = forms.DateField(input_formats=("%Y-%m-%d",))
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super(DateForm, self).__init__(*args, **kwargs)
 | 
			
		||||
        self.fields['start'].widget.attrs['data-date-format'] = "yyyy-mm-dd"
 | 
			
		||||
        self.fields['end'].widget.attrs['data-date-format'] = "yyyy-mm-dd"
 | 
			
		||||
@@ -1,77 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
from django.core import urlresolvers
 | 
			
		||||
from django.forms import fields
 | 
			
		||||
from django.forms import widgets
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicSelectWidget(widgets.Select):
 | 
			
		||||
    """
 | 
			
		||||
    A subclass of the ``Select`` widget which renders extra attributes for use
 | 
			
		||||
    in callbacks to handle dynamic changes to the available choices.
 | 
			
		||||
    """
 | 
			
		||||
    _data_add_url_attr = "data-add-item-url"
 | 
			
		||||
 | 
			
		||||
    def render(self, *args, **kwargs):
 | 
			
		||||
        add_item_url = self.get_add_item_url()
 | 
			
		||||
        if add_item_url is not None:
 | 
			
		||||
            self.attrs.update({self._data_add_url_attr: add_item_url})
 | 
			
		||||
        return super(DynamicSelectWidget, self).render(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_add_item_url(self):
 | 
			
		||||
        if callable(self.add_item_link):
 | 
			
		||||
            return self.add_item_link()
 | 
			
		||||
        try:
 | 
			
		||||
            if self.add_item_link_args:
 | 
			
		||||
                return urlresolvers.reverse(self.add_item_link,
 | 
			
		||||
                                            args=[self.add_item_link_args])
 | 
			
		||||
            else:
 | 
			
		||||
                return urlresolvers.reverse(self.add_item_link)
 | 
			
		||||
        except urlresolvers.NoReverseMatch:
 | 
			
		||||
            return self.add_item_link
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicChoiceField(fields.ChoiceField):
 | 
			
		||||
    """
 | 
			
		||||
    A subclass of ``ChoiceField`` with additional properties that make
 | 
			
		||||
    dynamically updating its elements easier.
 | 
			
		||||
 | 
			
		||||
    Notably, the field declaration takes an extra argument, ``add_item_link``
 | 
			
		||||
    which may be a string or callable defining the URL that should be used
 | 
			
		||||
    for the "add" link associated with the field.
 | 
			
		||||
    """
 | 
			
		||||
    widget = DynamicSelectWidget
 | 
			
		||||
 | 
			
		||||
    def __init__(self,
 | 
			
		||||
                 add_item_link=None,
 | 
			
		||||
                 add_item_link_args=None,
 | 
			
		||||
                 *args,
 | 
			
		||||
                 **kwargs):
 | 
			
		||||
        super(DynamicChoiceField, self).__init__(*args, **kwargs)
 | 
			
		||||
        self.widget.add_item_link = add_item_link
 | 
			
		||||
        self.widget.add_item_link_args = add_item_link_args
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DynamicTypedChoiceField(DynamicChoiceField, fields.TypedChoiceField):
 | 
			
		||||
    """ Simple mix of ``DynamicChoiceField`` and ``TypedChoiceField``. """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# FIXME: TableStep
 | 
			
		||||
# Should be in django 1.5.1 forms.widgets
 | 
			
		||||
class NumberInput(widgets.TextInput):
 | 
			
		||||
    input_type = 'number'
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 | 
			
		||||
 | 
			
		||||
# Copyright 2012 Nebula, 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.
 | 
			
		||||
 | 
			
		||||
import json
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from django import http
 | 
			
		||||
from django.views import generic
 | 
			
		||||
 | 
			
		||||
from horizon import exceptions
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ADD_TO_FIELD_HEADER = "HTTP_X_HORIZON_ADD_TO_FIELD"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ModalFormMixin(object):
 | 
			
		||||
    def get_template_names(self):
 | 
			
		||||
        if self.request.is_ajax():
 | 
			
		||||
            if not hasattr(self, "ajax_template_name"):
 | 
			
		||||
                # Transform standard template name to ajax name (leading "_")
 | 
			
		||||
                bits = list(os.path.split(self.template_name))
 | 
			
		||||
                bits[1] = "".join(("_", bits[1]))
 | 
			
		||||
                self.ajax_template_name = os.path.join(*bits)
 | 
			
		||||
            template = self.ajax_template_name
 | 
			
		||||
        else:
 | 
			
		||||
            template = self.template_name
 | 
			
		||||
        return template
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super(ModalFormMixin, self).get_context_data(**kwargs)
 | 
			
		||||
        if self.request.is_ajax():
 | 
			
		||||
            context['hide'] = True
 | 
			
		||||
        if ADD_TO_FIELD_HEADER in self.request.META:
 | 
			
		||||
            context['add_to_field'] = self.request.META[ADD_TO_FIELD_HEADER]
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ModalFormView(ModalFormMixin, generic.FormView):
 | 
			
		||||
    """
 | 
			
		||||
    The main view class from which all views which handle forms in Horizon
 | 
			
		||||
    should inherit. It takes care of all details with processing
 | 
			
		||||
    :class:`~horizon.forms.base.SelfHandlingForm` classes, and modal concerns
 | 
			
		||||
    when the associated template inherits from
 | 
			
		||||
    `horizon/common/_modal_form.html`.
 | 
			
		||||
 | 
			
		||||
    Subclasses must define a ``form_class`` and ``template_name`` attribute
 | 
			
		||||
    at minimum.
 | 
			
		||||
 | 
			
		||||
    See Django's documentation on the `FormView <https://docs.djangoproject.com
 | 
			
		||||
    /en/dev/ref/class-based-views/generic-editing/#formview>`_ class for
 | 
			
		||||
    more details.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def get_object_id(self, obj):
 | 
			
		||||
        """
 | 
			
		||||
        For dynamic insertion of resources created in modals, this method
 | 
			
		||||
        returns the id of the created object. Defaults to returning the ``id``
 | 
			
		||||
        attribute.
 | 
			
		||||
        """
 | 
			
		||||
        return obj.id
 | 
			
		||||
 | 
			
		||||
    def get_object_display(self, obj):
 | 
			
		||||
        """
 | 
			
		||||
        For dynamic insertion of resources created in modals, this method
 | 
			
		||||
        returns the display name of the created object. Defaults to returning
 | 
			
		||||
        the ``name`` attribute.
 | 
			
		||||
        """
 | 
			
		||||
        return obj.name
 | 
			
		||||
 | 
			
		||||
    def get_form(self, form_class):
 | 
			
		||||
        """
 | 
			
		||||
        Returns an instance of the form to be used in this view.
 | 
			
		||||
        """
 | 
			
		||||
        return form_class(self.request, **self.get_form_kwargs())
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        try:
 | 
			
		||||
            handled = form.handle(self.request, form.cleaned_data)
 | 
			
		||||
        except:
 | 
			
		||||
            handled = None
 | 
			
		||||
            exceptions.handle(self.request)
 | 
			
		||||
 | 
			
		||||
        if handled:
 | 
			
		||||
            if ADD_TO_FIELD_HEADER in self.request.META:
 | 
			
		||||
                field_id = self.request.META[ADD_TO_FIELD_HEADER]
 | 
			
		||||
                data = [self.get_object_id(handled),
 | 
			
		||||
                        self.get_object_display(handled)]
 | 
			
		||||
                response = http.HttpResponse(json.dumps(data))
 | 
			
		||||
                response["X-Horizon-Add-To-Field"] = field_id
 | 
			
		||||
            elif isinstance(handled, http.HttpResponse):
 | 
			
		||||
                return handled
 | 
			
		||||
            else:
 | 
			
		||||
                success_url = self.get_success_url()
 | 
			
		||||
                response = http.HttpResponseRedirect(success_url)
 | 
			
		||||
                # TODO(gabriel): This is not a long-term solution to how
 | 
			
		||||
                # AJAX should be handled, but it's an expedient solution
 | 
			
		||||
                # until the blueprint for AJAX handling is architected
 | 
			
		||||
                # and implemented.
 | 
			
		||||
                response['X-Horizon-Location'] = success_url
 | 
			
		||||
            return response
 | 
			
		||||
        else:
 | 
			
		||||
            # If handled didn't return, we can assume something went
 | 
			
		||||
            # wrong, and we should send back the form as-is.
 | 
			
		||||
            return self.form_invalid(form)
 | 
			
		||||
@@ -1,48 +0,0 @@
 | 
			
		||||
"""
 | 
			
		||||
Wrapper for loading templates from "templates" directories in panel modules.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.template.base import TemplateDoesNotExist
 | 
			
		||||
from django.template.loader import BaseLoader
 | 
			
		||||
from django.utils._os import safe_join
 | 
			
		||||
 | 
			
		||||
# Set up a cache of the panel directories to search.
 | 
			
		||||
panel_template_dirs = {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TemplateLoader(BaseLoader):
 | 
			
		||||
    is_usable = True
 | 
			
		||||
 | 
			
		||||
    def get_template_sources(self, template_name):
 | 
			
		||||
        bits = template_name.split(os.path.sep, 2)
 | 
			
		||||
        if len(bits) == 3:
 | 
			
		||||
            dash_name, panel_name, remainder = bits
 | 
			
		||||
            key = os.path.join(dash_name, panel_name)
 | 
			
		||||
            if key in panel_template_dirs:
 | 
			
		||||
                template_dir = panel_template_dirs[key]
 | 
			
		||||
                try:
 | 
			
		||||
                    yield safe_join(template_dir, panel_name, remainder)
 | 
			
		||||
                except UnicodeDecodeError:
 | 
			
		||||
                    # The template dir name wasn't valid UTF-8.
 | 
			
		||||
                    raise
 | 
			
		||||
                except ValueError:
 | 
			
		||||
                    # The joined path was located outside of template_dir.
 | 
			
		||||
                    pass
 | 
			
		||||
 | 
			
		||||
    def load_template_source(self, template_name, template_dirs=None):
 | 
			
		||||
        for path in self.get_template_sources(template_name):
 | 
			
		||||
            try:
 | 
			
		||||
                file = open(path)
 | 
			
		||||
                try:
 | 
			
		||||
                    return (file.read().decode(settings.FILE_CHARSET), path)
 | 
			
		||||
                finally:
 | 
			
		||||
                    file.close()
 | 
			
		||||
            except IOError:
 | 
			
		||||
                pass
 | 
			
		||||
        raise TemplateDoesNotExist(template_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_loader = TemplateLoader()
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,514 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Dimitar Dimitrov <dimitrov@linuxmail.org>, 2012
 | 
			
		||||
# Yasen Pramatarov <yasen@lindeas.com>, 2013
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: bg_BG\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Друго"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Влезте, за да продължите."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "Нямате права да достъпвате %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Нямате права. Опитайте да влезете отново."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "Паролата не е одобрена."
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Филтър"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Нямате права да %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Изтриване"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Изтрито"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Действия"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Изберете ред, преди да предприемете това действие."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Помощ"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Изход"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Вход"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Вход"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Записване"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Информация: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Внимание: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Успех: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Грешка: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Обобщение"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Обобщение"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Всички инстанции"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "Налично"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "Налично"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Текущ проект"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Изберете месец, за да намерите потреблението"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Изпращане"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Активни инстанции"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Отказ"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Без ограничение"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Налично"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "Паролата трябва да е между 8 и 18 символа."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Котки"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Котенца"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Тигри"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Кучета"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Кученца"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "Моето табло"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "Моят панел"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Админ панел"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "Грамадни мравки нападат Сан Франциско!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Проект"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Потребител"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Пръбно действие първо"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Инстанция"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Пробно действие второ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Пробно действие трето"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Админ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Администраторско действие"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Неправилен формат на IP-адрес"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Неправилна версия на IP-адрес"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Неправилна маска на подмрежата"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Обработване..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Запазване"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s приключи успешно."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s не приключи."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,73 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:09+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,513 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Sergi Almacellas <pokoli@gmail.com>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: ca\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Altre"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Identifique-se per continuar."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "No esteu autoritzat per accedir a %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Sense autorització. Torneu a intentar-ho."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "La contrasenya no ha estat acceptada"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filtre"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "No teniu per misos per a  %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "No es pot %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Eliminar"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Eliminat"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "L'attribut %(attr)s no existeix a %(obj)s"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "No hi ha itemas per mostrar"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Accions"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "No hi ha resultats per l'identificador \"%s\"."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Heu de seleccionar una fila abans de dur a terme aquesta acció."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "Identificat com"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Ajuda"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Sortir"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Usuari"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Identificació"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Registrar-se"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Informació:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Advertència:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Èxit:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Error: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Resum"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "Mostrant %(counter)s element"
 | 
			
		||||
msgstr[1] "Mostrar %(counter)s elements"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Resum"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "Usat"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "de"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Totes les instàncies"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "Disponible"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "Disponible"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] "Mostrant %(nav_items)s objjecte"
 | 
			
		||||
msgstr[1] "Mostrant %(nav_items)s objjectes"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] "Mostrant %(content_items)s objjecte"
 | 
			
		||||
msgstr[1] "Mostrant %(content_items)s objjectes"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Projecte actual"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Seleccioneu un mes per obtenir les seves estadístiques d'us"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Transmet"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Activar instàncies"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "Memòria activa"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "Hores de VCPU d'aquest més"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "GB-Hores d'aquest més"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Cancela"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Sense limit"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Disponible"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d byte"
 | 
			
		||||
msgstr[1] "%(size)d bytes"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "La contrasenya ha de tenir entre 8 i 18 caràcters."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "El meu tauler de control"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "El meu tauler"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Tauler d'administració"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Lot"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "En lots"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Item"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Items"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Davall"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Amunt"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Baixat"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Pujat"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Primera pestanya"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Pestanya retardada"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Pestanya deshabilitada"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Pestanya enraderida"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Pestanya amb la meua taula"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Pestanya d'error recuperables"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Projecte"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Usuari"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Acció de prova 1"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Instància"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Acció de prova 2"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Acció de prova 3"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Adminstració"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Acció de l'administració"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Format incorrecte per l'adreça IP"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Versió incorrecta de l'adreça IP"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Màscara de xarxa invàlida"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Processant..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Desa"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s completat correctament."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s no s'ha completat"
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,520 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# _AdamCz_ <a.skotnicky@tcpisek.cz>, 2013
 | 
			
		||||
# pavlija7 <pavlk.jakub@gmail.com>, 2013
 | 
			
		||||
# Jaroslav Henner <jaroslav.henner@gmail.com>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: cs\n"
 | 
			
		||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Ostatní"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "K pokračování je nutno se přihlásit."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "Nejste autorizován k přístupu %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Nejste autorizován. Prosím pokuste se přihlásit znovu."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr "Navigační položka"
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr "Vyberte %s pro prohlížení"
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "Heslo nebylo akceptováno"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filtr"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr "%(action)s %(data_type)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr "nedostupné"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Nemáte oprávnění pro %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Není možné provést %(action)s na %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Vymazat"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Smazáno"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "Atribut %(attr)s neexistuje na %(obj)s."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "Žádné položky k zobrazení."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Akce"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "Nic s id \"%s\" nebylo nalezeno."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Pro provedení akce prosím vyberte řádky."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "Přihlášen jako"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Nápověda"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Odhlásit"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Přihlášení"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Přihlásit"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr "Nemáte povolení pro přístup k:"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr "Přihlašte se jako jiný uživatel nebo se vraťte k"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "domovská stránka"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Registrovat"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Info:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Varování:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Úspěch:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Chyba:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Souhrn"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "Zobrazuji %(counter)s položku"
 | 
			
		||||
msgstr[1] "Zobrazuji %(counter)s položek"
 | 
			
		||||
msgstr[2] "Zobrazuji %(counter)s položky"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "Více"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Souhrn kvóty"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "Použito"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "z"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Dostupné instance"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "Dostupné vCPU"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "Dostupná RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr "Dostupné volumes"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr "Dostupný diskový prostor"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] "Zobrazuji %(nav_items)s položku"
 | 
			
		||||
msgstr[1] "Zobrazuji %(nav_items)s položky"
 | 
			
		||||
msgstr[2] "Zobrazuji %(nav_items)s položky"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] "Zobrazuji %(content_items)s položku"
 | 
			
		||||
msgstr[1] "Zobrazuji %(content_items)s položky"
 | 
			
		||||
msgstr[2] "Zobrazuji %(content_items)s položky"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Současný projekt"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Vyberte měsíc pro zobrazení jeho využití."
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Potvrdit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Aktivní instance"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "Využívaná RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "VCPU-hodin za tento měsíc"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "GB-hodiny za tento měsíc"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Zrušit"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Bez limitu"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Dostupné"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d byte"
 | 
			
		||||
msgstr[1] "%(size)d bytes"
 | 
			
		||||
msgstr[2] "%(size)d bytes"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
msgstr[2] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "Heslo musí mít od 8 do 18 znaků."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Roztomilé kočky"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Divoké kočky"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Kočky"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Koťata"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tygři"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Psi"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Štěňata"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "Můj Dashboard"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "Můj panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Admin panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "Obří mravenci utočí na San Francisco!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr "Už jsme v bezpečí před maravenci! Běž <a>sem</a>!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Dávka"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "Dávkově"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Položka"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Položek"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Dolů"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Nahoru"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Sestřelený"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Nahozený"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr "Žádná Action Table"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr "Jedna tabulka"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Záložka jedna"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Delayed Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Disabled Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Disallowed Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Záložka s My Table"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Recoverable Error Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Projekt"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Uživatel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Testovat Action One"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Instance"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Testovat Action Two"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Testovat Action Three"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Admin"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Admin akce"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Nekorektní formát IP adresy"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Špatná verze IP adresy"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Špatná subnet maska"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Zpracovávám..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr "Vše dostupné"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "Členové"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr "Nedostupné"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "Žádní členové."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Uložit"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s úspěšně dokončeno"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s nedokončeno"
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,514 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Gabriel Hurley <gabriel@strikeawe.com>, 2012
 | 
			
		||||
# johnpostlethwait <john.postlethwait@gmail.com>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: en\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Other"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Please log in to continue."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "You are not authorized to access %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Unauthorized. Please try logging in again."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "Password is not accepted"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filter"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Unable to %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Delete"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Deleted"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "No items to display."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Actions"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "No match returned for the id \"%s\"."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Please select a row before taking that action."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Info: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Warning: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Success: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Error: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Summary"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "Displaying %(counter)s item"
 | 
			
		||||
msgstr[1] "Displaying %(counter)s items"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Current Project"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Select a month to query its usage"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Submit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Active Instances"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "This Month's VCPU-Hours"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "This Month's GB-Hours"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Cancel"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "No Limit"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Available"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d byte"
 | 
			
		||||
msgstr[1] "%(size)d bytes"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "Password must be between 8 and 18 characters."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Cute Cats"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Fierce Cats"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Cats"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Kittens"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tigers"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Dogs"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Puppies"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "My Dashboard"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "My Panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Admin Panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "Giant ants are attacking San Francisco!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Batch"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "Batched"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Item"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Items"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Down"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Up"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Downed"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Upped"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Tab One"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Delayed Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Disabled Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Disallowed Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Tab With My Table"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Recoverable Error Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Project"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "User"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Test Action One"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Instance"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Test Action Two"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Test Action Three"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Admin"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Admin Action"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Incorrect format for IP address"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Invalid version for IP address"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Invalid subnet mask"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Processing..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Save"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s completed successfully."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s did not complete."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,73 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:09+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,513 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Andi Chandler <andi@gowling.com>, 2013
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-30 22:33+0000\n"
 | 
			
		||||
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: en_GB\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Other"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Please log in to continue."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "You are not authorised to access %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Unauthorised. Please try logging in again."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr "Navigation Item"
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr "Select a %s to browse."
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "Password is not accepted"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filter"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr "%(action)s %(data_type)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr "N/A"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Unable to %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Delete"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Deleted"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "The attribute %(attr)s does not exist on %(obj)s."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "No items to display."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Actions"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "No match returned for the id \"%s\"."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Please select a row before taking that action."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "Logged in as"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Help"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Sign Out"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Login"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Log In"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr "You do not have permissions to access:"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr "Login as different user or go back to"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "home page"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Sign In"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Info: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Warning: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Success: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Error: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Summary"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "More"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Quota Summary"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "Used"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "of"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Available Instances"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "Available vCPUs"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "Available RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr "Available volumes"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr "Available volume storage"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Current Project"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Select a month to query its usage"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Submit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Active Instances"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "Active RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "This Month's VCPU-Hours"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "This Month's GB-Hours"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Cancel"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "No Limit"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Available"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "Password must be between 8 and 18 characters."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Cute Cats"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Fierce Cats"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Cats"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Kittens"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tigers"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Dogs"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Puppies"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "My Dashboard"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "My Panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Admin Panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "Giant ants are attacking San Francisco!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Batch"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "Batched"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Item"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Items"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Down"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Up"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Downed"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Upped"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr "No Actions Table"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr "Single Table"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Tab One"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Delayed Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Disabled Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Disallowed Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Tab With My Table"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Recoverable Error Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Project"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "User"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Test Action One"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Instance"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Test Action Two"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Test Action Three"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Admin"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Admin Action"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Incorrect format for IP address"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Invalid version for IP address"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Invalid subnet mask"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Processing..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr "All available"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "Members"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr "None available."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "No members."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Save"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s completed successfully."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s did not complete."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,518 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Alberto Molina Coballes <alb.molina@gmail.com>, 2012-2013
 | 
			
		||||
# Alberto Molina Coballes <alb.molina@gmail.com>, 2012
 | 
			
		||||
# emujicad <emujicad@gmail.com>, 2013
 | 
			
		||||
# Gabriel Hurley <gabriel@strikeawe.com>, 2012
 | 
			
		||||
# zeus <jonathan.abdiel@gmail.com>, 2012
 | 
			
		||||
# Pedro Navarro Pérez <pednape@gmail.com>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: es\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Otro"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Por favor inicie sesión para continuar."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "No está autorizado para acceder a %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "No autorizado. Por favor ingrese de nuevo."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr "Ítem de Navegación"
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr "Seleccionar una %s para navegar."
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "La contraseña no se ha aceptado"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filtrar"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr "%(action)s %(data_type)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr "N/A"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "No tiene permiso para %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "No ha sido posible %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Borrar"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Borrado"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "El atributo %(attr)s no existe en %(obj)s."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "No hay ítems que mostrar"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Acciones"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "Ninguna coincidencia para el id \"%s\"."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Por favor, seleccione una fila antes de realizar la acción."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "Identificado como"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Ayuda"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Salir"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Ingresar"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Ingresar"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr "No tiene permisos para acceder:"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr "Ingresar como otro usuario o volver"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "Inicio"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Darse de alta"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Info:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Aviso:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Correcto:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Error: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Resumen"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "Mostrando %(counter)s item"
 | 
			
		||||
msgstr[1] "Mostrando %(counter)s items"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "Más"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Resumen de cuotas"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "Usado"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "de"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Instancias disponibles"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "vCPUs disponibles"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "RAM Disponible"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr "Volúmenes disponibles"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr "Almacenamiento de volúmenes disponible"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] "Mostrando %(nav_items)s item"
 | 
			
		||||
msgstr[1] "Mostrando %(nav_items)s ítems"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] "Mostrando %(content_items)s item"
 | 
			
		||||
msgstr[1] "Mostrando %(content_items)s ítems"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Proyecto Actual"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Seleccione un mes para el que solicitar uso"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Enviar"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Instancias Activas"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "RAM Activa"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "Horas VCPU de este mes"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "Horas GB de este mes"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Cancelar"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Sin límite"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Disponible"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d byte"
 | 
			
		||||
msgstr[1] "%(size)d bytes"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "La contraseña debe tener entre 8 y 18 caracteres."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Gatos bonitos"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Gatos feroces"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Gatos"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Gatitos"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tigres"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Perros"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Perritos"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "Mi Dashboard"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "Mi Panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Panel de Administración"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "¡Hormigas gigantes están atacando Sevilla!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr "¡Estamos a salvo de las hormigas! ¡Vaya <a>aquí</a>!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Lote"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "Por lotes"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Ítem"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Ítems"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Abajo"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Arriba"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Bajados"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Subidos"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr "No hay tabla de acciones"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr "Tabla única"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Pestaña Uno"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Pestaña Retrasada"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Pestaña Deshabilitada"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Pestaña no Permitida"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Pestaña con mi tabla"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Pestaña de errores recuperables"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Proyecto"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Usuario"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Acción de prueba Uno"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Instancia"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Acción de prueba Dos"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Acción de prueba Tres"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Admin"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Acción de Administrador"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Formato incorrecto de dirección IP"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Versión no válida de dirección IP"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Máscara de red no válida"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Procesando..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr "Todas disponibles"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "Miembros"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr "Ninguna disponible."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "Sin miembros."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Guardar"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s completado correctamente."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s no completado."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,74 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:09+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,513 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# copard <ari.karhunen@pard.co>, 2013
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-05-02 12:39+0000\n"
 | 
			
		||||
"Last-Translator: copard <ari.karhunen@pard.co>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: fi_FI\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Toinen"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Kirjaudu jatkaaksesi"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "Et ole oikeutettu päästäksesi %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Ei oikeutettu: Yritä kirjautumista uudelleen."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr "Navigaatio yksikkö"
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr "valitse %s selataksesi."
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "Salasanaa ei hyväksytty"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filtteri"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr "%(action)s %(data_type)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr "N/A"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Sinulla ei ole oikeuksia %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Ei voida %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Poista"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Poistettu"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "Arvoa %(attr)s ei löydy %(obj)s. "
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "Ei näytettävää."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Toiminnot"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "ID \"%s\" ei palauttanut osumia."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Valitse rivi ennen toiminnon tekemistä."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "Kirjauduttu käyttäjänä"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Apua"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Kirjaudu Ulos"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Kirjaudu"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Kirjaudu"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr "Teillä ei ole oikeuksia päästäksenne:"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr "Kirjaudu toisena käyttäjänä palataksesi"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "kotisivu"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Kirjaudu"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Info:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Varoitus:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Onnistui:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Virhe:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "yhteenveto"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "Näytetään kohde %(counter)s "
 | 
			
		||||
msgstr[1] "Näytetään %(counter)s kohdetta"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "Lisää"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Kiintiö yleiskatsaus"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "käytetty"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "kohteesta"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Saatavilla olevat Instanssit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "Saatavilla olevat vCPU:t"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "Saatavilla oleva RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr "Saatavilla olevat verkkolevyt"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr "Saatavilla oleva verkkolevykapasiteetti"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] "Näytetään %(nav_items)s kohde"
 | 
			
		||||
msgstr[1] "Näytetään %(nav_items)s kohdetta"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] "Näytetään %(content_items)s kohde"
 | 
			
		||||
msgstr[1] "Näytetään %(content_items)s kohdetta"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Nykyinen projekti"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Valitse kuukausi katsoaksesi käyttöä"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Lähetä"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Aktivoi instanssit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "Käytetty RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "Tämän kuukauden VCPU-tunnit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "Tämän kuukauden GB-tunnit"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Keskeytä"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Ei rajaa"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Saatavilla"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d tavu"
 | 
			
		||||
msgstr[1] "%(size)d tavua"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "Salasanan täytyy olla 8 ja 18 merkin väliltä."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "meow meow kissat."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Hurjia kisuja"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Kisuja"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Pikku kisuja"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tiikereitä roar."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Koiria"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Pentuja. aww.."
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "Minun hallintapaneeli"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "Minun Paneeli"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Admin paneeli"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "YAY. Let the giant ants attack San FernandSisco."
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr "Olemme turvassa muurahaisilta, MENE <a>tänne</a>|"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Sarja"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "Sarjoitettu"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "kohta"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "kohdat"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Alhaalla"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Ylhäällä"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Pudotettu"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Nostettu"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr "Ei tehtävätauluja"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr "Yksittäinen taulu"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Ensimmäinen Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Viivästetty Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Poistettu Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Estettu Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Tab minun taulussa"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Palautettava Virhe Tab"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Projekti"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Käyttäjä"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "ensimmäinen Testitoimi"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Insanssi"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "toinen testitoimi"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "kolmas testitoimi"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Admin"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Admin toimi"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Väärä formaatti IP-osoitteelle."
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Väärä versio IP-osoitteesta"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Väärä aliverkonpeite."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Käsitellään..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr "Kaikki saatavilla"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "Käyttäjät"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr "Ei mitään saatavilla."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "Ei käyttäjiä"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Tallenna"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s tehtiin onnistuneesti."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s ei valmistunut."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,510 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
#
 | 
			
		||||
# Translators:
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2012-05-08 20:22+0000\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
"Language: fr\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,74 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,515 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012
 | 
			
		||||
# kelemeng <kelemeng@gnome.hu>, 2013
 | 
			
		||||
# marton.kiss <marton.kiss@gmail.com>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: hu\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Egyéb"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Lépjen be a folytatáshoz."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "Nincsen engedélyezve a hozzáférés ehhez: %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Jogosulatlan hozzáférés. Próbáljon meg belépni újra."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr "Navigációs elem"
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr "A böngészéshez válasszon egy %s elemet"
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "A jelszó nincs elfogadva"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Szűrő"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr "%(action)s %(data_type)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr "---"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Nincsen hozzáférése ehhez: %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Nem hajtható végre: %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Törlés"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Törölve"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "A(z) %(attr)s attribútum nem létezik ezen: %(obj)s."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "Nincs megjeleníthető elem."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Műveletek"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "Nincs találat a(z) „%s” azonosítóhoz."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Válasszon ki egy sort a művelet végrehajtása előtt."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "Belépve mint"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "Súgó"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "Kijelentkezés"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "Bejelentkezés"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "Bejelentkezés"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr "Nincs jogosultsága elérni:"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr "Jelentkezzen be másik felhasználóként, vagy lépjen vissza a"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "kezdőlapra"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "Bejelentkezés"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Információ: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Figyelmeztetés: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Siker: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Hiba: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Összegzés"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "%(counter)s tétel megjelenítése"
 | 
			
		||||
msgstr[1] "%(counter)s tétel megjelenítése"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "Több"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "Kvóta összefoglaló"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "Használt"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "/"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "Elérhető példányok"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "Elérhető vCPU-k"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "Szabad memória"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr "Elérhető kötetek"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr "Elérhető tárhely"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] "%(nav_items)s tétel megjelenítése"
 | 
			
		||||
msgstr[1] "%(nav_items)s tétel megjelenítése"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] "%(content_items)s tétel megjelenítése"
 | 
			
		||||
msgstr[1] "%(content_items)s tétel megjelenítése"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Jelenlegi projekt"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "Válasszon egy hónapot a felhasználási adatok lekéréséhez"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "Beküldés"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Aktív példányok"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "Aktív memória"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "Havi vCPU-óra felhasználás"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "Havi GB-óra felhasználás"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Mégse"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Nincs korlát"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Elérhető"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d bájt"
 | 
			
		||||
msgstr[1] "%(size)d bájt"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "A jelszónak 8 és 18 karakter közöttinek kell lennie."
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Cuki macskák"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Morcos macskák"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Macskák"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Kismacskák"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tigrisek"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Kutyák"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Kutyakölykök"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "Vezérlőpult"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "Panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Adminisztrációs panel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "Óriás hangyák támadják San Francisco-t!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr "Biztonságban vagyunk a hangyáktól! Lépjen <a>ide</a>!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "Kötegelt"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "Kötegelt"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Tétel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Tételek"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "Le"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "Fel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "Csökkentve"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "Növelve"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr "Nincs műveletek táblázat"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr "Egy tábla"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "Első fül"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "Késleltetett fül"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "Letiltott fül"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "Nem engedélyezett fül"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "Saját táblázatom füle"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "Helyreállítható hiba fül"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Projekt"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Felhasználó"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Első teszt művelet"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Példány"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Második teszt művelet"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Harmadik teszt művelet"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Adminisztrátor"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Adminisztrátori művelet"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Helytelen IP-cím formátum"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Érvénytelen IP-cím változat"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Érvénytelen alhálózati maszk"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Feldolgozás…"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr "Összes elérhető"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "Tagok"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr "Nincs elérhető."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "Nincsenek tagok."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Mentés"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s sikeresen befejeződött."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s nem fejeződött be."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,515 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Loris Strozzini <lstrozzini@gmail.com>, 2012
 | 
			
		||||
# Salvatore Orlando <sorlando@nicira.com>, 2012
 | 
			
		||||
# Stefano Maffulli <smaffulli@gmail.com>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: it\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Altro"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Accedi per continuare"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "Accesso non autorizzato a %s"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Non autorizzato. Ritentare il login."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "La password non è stata accettata."
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filtro"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "Non si dispone dei permessi per %(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Elimina"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Eliminato"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "L'attributo %(attr)s non esiste in %(obj)s"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "Nessun elemento da visualizzare"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Azioni"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "Nessuna corrispondenza restituita per l'identificativo \"%s\""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "Per cortesia, selezionare una riga prima di eseguire tale azione."
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Attenzione:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Successo:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Errore:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "Riepilogo"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "Progetto corrente"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "Istanze attive"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Annulla"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Gattini carini"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Gattacci feroci"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Gatti"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Micini"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tigri"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Cani"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Cucciolini"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "Scarrafoni giganti stanno attaccando Napoli!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Progetto"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Utente"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Istanza"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Amministratore"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Formato incorretto per l'indirizzo IP"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Versione dell'indirizzo IP non valida"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Maschera sottorete non valida."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Attendere prego..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Salva"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s completato correttamente."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s non completato."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,74 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:09+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,511 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Akihiro MOTOKI <amotoki@gmail.com>, 2013
 | 
			
		||||
# bi.yamagata <bi.yamagata@gmail.com>, 2012
 | 
			
		||||
# bi.yamagata <bi.yamagata@gmail.com>, 2012
 | 
			
		||||
# Tomoyuki KATO <tomo@dream.daynight.jp>, 2012-2013
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-05-07 10:24+0000\n"
 | 
			
		||||
"Last-Translator: Akihiro MOTOKI <amotoki@gmail.com>\n"
 | 
			
		||||
"Language-Team: Japanese (http://www.transifex.com/projects/p/openstack/language/ja/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: ja\n"
 | 
			
		||||
"Plural-Forms: nplurals=1; plural=0;\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "その他"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "続行するには、ログインしてください。"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "%s へのアクセスが許可されていません。"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "認証されていません。もう一度ログインしてください。"
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr "ナビゲーション項目"
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr "表示する %s を選択してください。"
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "パスワードを受け付けられません"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "フィルター"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr "%(data_type)sの%(action)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr "N/A"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s を実行する権限がありません: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s を実行できません: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "削除"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "削除しました"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr "%(obj)s に 属性 %(attr)s が存在しません。"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "表示する項目がありません。"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "アクション"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "ID \"%s\" に一致するものがありません。"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr "このアクションを実行する前に、対象を選択してください。"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr "次の役割でログイン中"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "ヘルプ"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "ログアウト"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "ログイン"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr "ログイン"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr "アクセスする権限がありません: "
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr "他のユーザーとしてログインしてください。または、戻ってください。"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "ホームページ"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr "ログイン"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "情報: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "警告: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "成功: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "エラー: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "概要"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "%(counter)s 項目の表示中"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "さらに"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "クォータ概要"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "使用済み"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr "/"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr "利用可能なインスタンス"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr "利用可能な仮想 CPU"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "利用可能なメモリー"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr "利用可能なボリューム"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr "利用可能なボリュームストレージ"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] "%(nav_items)s 項目の表示中"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] "%(content_items)s 項目の表示中"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr "現在のプロジェクト"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr "使用量を問い合わせる月の選択"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "送信"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "稼働中のインスタンス"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "使用中のメモリー"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "今月の仮想 CPU 時間"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "今月の GB 時間"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "取り消し"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr "Horizon"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "制限なし"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "利用可能"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d バイト"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr "パスワードは 8 文字から 18 文字である必要があります。"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "かわいいネコ"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "獰猛なネコ"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "ネコ"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "子ネコ"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "トラ"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "イヌ"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "子イヌ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "マイダッシュボード"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "マイパネル"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "管理パネル"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr "巨大な蟻がサンフランシスコを攻撃しています!"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr "私たちは蟻から守られています ! <a>こちらへ</a> !"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "バッチ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "バッチを実行しました"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "項目"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "項目"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "下へ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "上へ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr "下げました"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr "上げました"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr "アクション表がありません"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr "単一テーブル"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr "タブ 1"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr "遅延されたタブ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr "無効化されたタブ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr "禁止されたタブ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr "テーブルのあるタブ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr "修復可能なエラーのタブ"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "プロジェクト"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "ユーザー"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "テストアクション 1"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "インスタンス"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "テストアクション 2"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "テストアクション 3"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "管理"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "管理アクション"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "不正な形式の IP アドレス"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "無効な IP アドレスのバージョン"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "無効なサブネットマスク"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "処理中..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr "利用可能な全項目"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "メンバー"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr "利用可能な項目がありません。"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "メンバーがいません。"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "保存"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s が正常に完了しました。"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s が完了しませんでした。"
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,73 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:09+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=1; plural=0\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,508 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Nika Chkhikvishvili <frrrredo@gmail.com>, 2013
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: ka_GE\n"
 | 
			
		||||
"Plural-Forms: nplurals=1; plural=0;\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "სხვა"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "ფილტრი"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "წაშლა"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "წაშლილი"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "მოქმედებები"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr "დახმარება"
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr "გამისვლა"
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr "შესვლა"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr "მთავარი გვერდი"
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "გაფრთხილება:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "წარმატება:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr "ჯამი"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr "მეტი"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr "კვოტის ჯამი"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr "გამოყენებული"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr "ხელმისაწვდომი RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr "აქტიური RAM"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "ჩემი პანელი"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "ადმინ პანელი"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr "ქვევით"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr "ზევით"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "პროექტი"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "მომხმარებელი"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "წევრები"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr "არ არაის წევრები."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "შენახვა"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,509 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# bluejay.kr <bluejay.ahn@gmail.com>, 2012
 | 
			
		||||
# Sungjin Gang <potopro@gmail.com>, 2013
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-05-03 12:23+0000\n"
 | 
			
		||||
"Last-Translator: Sungjin Gang <potopro@gmail.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: ko_KR\n"
 | 
			
		||||
"Plural-Forms: nplurals=1; plural=0;\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "다른"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "로그인을 해주세요."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "%s에 접근 권한이 없습니다. "
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "인증되지 않았습니다. 다시 로깅해주시기 바랍니다. "
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "필터"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s에 관한 권한이 없습니다.: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s를 사용할 수 없습니다.: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr "%(action)s: %(objs)s"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "삭제"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "삭제했음"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr "표시할 항목이 없습니다."
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "작동"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr "일치하는 id \"%s\"를 반환"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "정보:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "주의:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "완료:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "에러:"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] "%(counter)s 항목 표시"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr "제출"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr "작동중인 인스턴스"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr "한달간 VCPU-시간"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr "한달간 GB-시간"
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "취소"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "유한한"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "사용가능한"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d bytes"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "내 대시보드"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "내 판넬"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "관리자 판넬"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr "일괄 처리"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr "일괄 처리된"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "항목"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "항목들"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "프로젝트"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "사용자"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "인스턴스"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "관리자"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "관리자 액션"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "저장"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,73 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,514 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# 
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Translators:
 | 
			
		||||
# Erik-Martijn Kasimier <erik.kasimier@nouveaumedia.nl>, 2012
 | 
			
		||||
# Erik-Martijn Kasimier <erik.kasimier@nouveaumedia.nl>, 2012
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: Horizon\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: https://launchpad.net/horizon\n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+0000\n"
 | 
			
		||||
"PO-Revision-Date: 2013-04-29 08:33+0000\n"
 | 
			
		||||
"Last-Translator: Gabriel Hurley <gabriel@strikeawe.com>\n"
 | 
			
		||||
"Language-Team: English (http://www.transifex.com/projects/p/openstack/language/en/)\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Language: nl_NL\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: base.py:424
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Andere"
 | 
			
		||||
 | 
			
		||||
#: decorators.py:55
 | 
			
		||||
msgid "Please log in to continue."
 | 
			
		||||
msgstr "Log in om door te gaan."
 | 
			
		||||
 | 
			
		||||
#: decorators.py:87
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You are not authorized to access %s"
 | 
			
		||||
msgstr "Je bent niet geauthoriseerd om %s te bekijken"
 | 
			
		||||
 | 
			
		||||
#: exceptions.py:283
 | 
			
		||||
msgid "Unauthorized. Please try logging in again."
 | 
			
		||||
msgstr "Je bent niet geautoriseerd. Probeer opnieuw in te loggen."
 | 
			
		||||
 | 
			
		||||
#: browsers/base.py:90
 | 
			
		||||
msgid "Navigation Item"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: browsers/views.py:42
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Select a %s to browse."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: conf/default.py:29
 | 
			
		||||
msgid "Password is not accepted"
 | 
			
		||||
msgstr "Wachtwoord is niet geaccepteerd"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:349
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr "Filter"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:527
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s %(data_type)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:561
 | 
			
		||||
msgid "N/A"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:589
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "You do not have permission to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:595
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Unable to %(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:601
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(action)s: %(objs)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:611
 | 
			
		||||
msgid "Delete"
 | 
			
		||||
msgstr "Verwijder"
 | 
			
		||||
 | 
			
		||||
#: tables/actions.py:612
 | 
			
		||||
msgid "Deleted"
 | 
			
		||||
msgstr "Verwijderd"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:275
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "The attribute %(attr)s doesn't exist on %(obj)s."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:748
 | 
			
		||||
msgid "No items to display."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:852
 | 
			
		||||
msgid "Actions"
 | 
			
		||||
msgstr "Acties"
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1035
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "No match returned for the id \"%s\"."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: tables/base.py:1165
 | 
			
		||||
msgid "Please select a row before taking that action."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:3
 | 
			
		||||
msgid "Logged in as"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:5
 | 
			
		||||
msgid "Help"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/_header.html:7
 | 
			
		||||
msgid "Sign Out"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/splash.html:7 templates/auth/login.html:4
 | 
			
		||||
msgid "Login"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:4
 | 
			
		||||
msgid "Log In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:14
 | 
			
		||||
msgid "You don't have permissions to access:"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:16
 | 
			
		||||
msgid "Login as different user or go back to"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:17
 | 
			
		||||
msgid "home page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/auth/_login.html:27
 | 
			
		||||
msgid "Sign In"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:7
 | 
			
		||||
msgid "Info: "
 | 
			
		||||
msgstr "Informatie: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:13
 | 
			
		||||
msgid "Warning: "
 | 
			
		||||
msgstr "Waarschuwing: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:19
 | 
			
		||||
msgid "Success: "
 | 
			
		||||
msgstr "Succesvol: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/_messages.html:25
 | 
			
		||||
msgid "Error: "
 | 
			
		||||
msgstr "Error: "
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:54
 | 
			
		||||
msgid "Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table.html:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(counter)s item"
 | 
			
		||||
msgid_plural "Displaying %(counter)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_data_table_row_actions.html:10
 | 
			
		||||
msgid "More"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:4
 | 
			
		||||
msgid "Quota Summary"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Used"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "of"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:5
 | 
			
		||||
msgid "Available Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:8
 | 
			
		||||
msgid "Available vCPUs"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:11
 | 
			
		||||
msgid "Available RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:15
 | 
			
		||||
msgid "Available volumes"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_quota_summary.html:18
 | 
			
		||||
msgid "Available volume storage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:10
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(nav_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(nav_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_resource_browser.html:11
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "Displaying %(content_items)s item"
 | 
			
		||||
msgid_plural "Displaying %(content_items)s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_sidebar.html:14
 | 
			
		||||
msgid "Current Project"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:5
 | 
			
		||||
msgid "Select a month to query its usage"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:9
 | 
			
		||||
msgid "Submit"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:14
 | 
			
		||||
msgid "Active Instances"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:15
 | 
			
		||||
msgid "Active RAM"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:16
 | 
			
		||||
msgid "This Month's VCPU-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_usage_summary.html:17
 | 
			
		||||
msgid "This Month's GB-Hours"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templates/horizon/common/_workflow.html:33
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Annuleren"
 | 
			
		||||
 | 
			
		||||
#: templatetags/branding.py:35
 | 
			
		||||
msgid "Horizon"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:109
 | 
			
		||||
msgid "No Limit"
 | 
			
		||||
msgstr "Geen limiet"
 | 
			
		||||
 | 
			
		||||
#: templatetags/horizon.py:111 templatetags/horizon.py:113
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Beschikbaar"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:45
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d byte"
 | 
			
		||||
msgid_plural "%(size)d bytes"
 | 
			
		||||
msgstr[0] "%(size)d byte"
 | 
			
		||||
msgstr[1] "%(size)d bytes"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:49
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(size)d"
 | 
			
		||||
msgid_plural "%(size)d"
 | 
			
		||||
msgstr[0] "%(size)d"
 | 
			
		||||
msgstr[1] "%(size)d"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:52
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s KB"
 | 
			
		||||
msgstr "%s KB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:55
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s MB"
 | 
			
		||||
msgstr "%s MB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:58
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s GB"
 | 
			
		||||
msgstr "%s GB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:61
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s TB"
 | 
			
		||||
msgstr "%s TB"
 | 
			
		||||
 | 
			
		||||
#: templatetags/sizeformat.py:63
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s PB"
 | 
			
		||||
msgstr "%s PB"
 | 
			
		||||
 | 
			
		||||
#: test/settings.py:114
 | 
			
		||||
msgid "Password must be between 8 and 18 characters."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:8
 | 
			
		||||
msgid "Cute Cats"
 | 
			
		||||
msgstr "Schattige katten"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:14
 | 
			
		||||
msgid "Fierce Cats"
 | 
			
		||||
msgstr "Felle katten"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/dashboard.py:19
 | 
			
		||||
msgid "Cats"
 | 
			
		||||
msgstr "Katten"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/kittens/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/kittens/templates/kittens/index.html:6
 | 
			
		||||
msgid "Kittens"
 | 
			
		||||
msgstr "Kittens"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/cats/tigers/panel.py:9
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:3
 | 
			
		||||
#: test/test_dashboards/cats/tigers/templates/tigers/index.html:6
 | 
			
		||||
msgid "Tigers"
 | 
			
		||||
msgstr "Tijgers"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/dashboard.py:7
 | 
			
		||||
msgid "Dogs"
 | 
			
		||||
msgstr "Honden"
 | 
			
		||||
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/panel.py:9
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:3
 | 
			
		||||
#: test/test_dashboards/dogs/puppies/templates/puppies/index.html:6
 | 
			
		||||
msgid "Puppies"
 | 
			
		||||
msgstr "Puppy's"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:39
 | 
			
		||||
msgid "My Dashboard"
 | 
			
		||||
msgstr "Mijn dashboard"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:45
 | 
			
		||||
msgid "My Panel"
 | 
			
		||||
msgstr "Alle instances"
 | 
			
		||||
 | 
			
		||||
#: test/tests/base.py:51
 | 
			
		||||
msgid "Admin Panel"
 | 
			
		||||
msgstr "Beheerderspaneel"
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:32
 | 
			
		||||
msgid "Giant ants are attacking San Francisco!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/messages.py:46
 | 
			
		||||
msgid "We are now safe from ants! Go <a>here</a>!"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:107
 | 
			
		||||
msgid "Batch"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:108
 | 
			
		||||
msgid "Batched"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:109 test/tests/tables.py:120
 | 
			
		||||
msgid "Item"
 | 
			
		||||
msgstr "Item"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:110 test/tests/tables.py:121
 | 
			
		||||
msgid "Items"
 | 
			
		||||
msgstr "Items"
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Down"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:118
 | 
			
		||||
msgid "Up"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Downed"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:119
 | 
			
		||||
msgid "Upped"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:187
 | 
			
		||||
msgid "No Actions Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tables.py:684
 | 
			
		||||
msgid "Single Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:36
 | 
			
		||||
msgid "Tab One"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:42
 | 
			
		||||
msgid "Delayed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:49
 | 
			
		||||
msgid "Disabled Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:58
 | 
			
		||||
msgid "Disallowed Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:76
 | 
			
		||||
msgid "Tab With My Table"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/tabs.py:85
 | 
			
		||||
msgid "Recoverable Error Tab"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:43
 | 
			
		||||
msgid "Project"
 | 
			
		||||
msgstr "Project"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:44
 | 
			
		||||
msgid "User"
 | 
			
		||||
msgstr "Gebruiker"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:47
 | 
			
		||||
msgid "Test Action One"
 | 
			
		||||
msgstr "Testactie één"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:61
 | 
			
		||||
msgid "Instance"
 | 
			
		||||
msgstr "Instance"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:64
 | 
			
		||||
msgid "Test Action Two"
 | 
			
		||||
msgstr "Testactie twee"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:72
 | 
			
		||||
msgid "Test Action Three"
 | 
			
		||||
msgstr "Testactie drie"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:77
 | 
			
		||||
msgid "Admin"
 | 
			
		||||
msgstr "Beheerder"
 | 
			
		||||
 | 
			
		||||
#: test/tests/workflows.py:80
 | 
			
		||||
msgid "Admin Action"
 | 
			
		||||
msgstr "Beheerdersactie"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:46
 | 
			
		||||
msgid "Incorrect format for IP address"
 | 
			
		||||
msgstr "Onjuist formaat IP adres"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:47
 | 
			
		||||
msgid "Invalid version for IP address"
 | 
			
		||||
msgstr "Invalide versie IP adres"
 | 
			
		||||
 | 
			
		||||
#: utils/fields.py:48
 | 
			
		||||
msgid "Invalid subnet mask"
 | 
			
		||||
msgstr "Invalide subnet mask"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:71
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Verwerken..."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:467
 | 
			
		||||
msgid "All available"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:468
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:469
 | 
			
		||||
msgid "None available."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:470
 | 
			
		||||
msgid "No members."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:569
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Opslaan"
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:570
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s completed successfully."
 | 
			
		||||
msgstr "%s succesvol afgerond."
 | 
			
		||||
 | 
			
		||||
#: workflows/base.py:571
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%s did not complete."
 | 
			
		||||
msgstr "%s was niet voltooid."
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1,73 +0,0 @@
 | 
			
		||||
# SOME DESCRIPTIVE TITLE.
 | 
			
		||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
 | 
			
		||||
# This file is distributed under the same license as the PACKAGE package.
 | 
			
		||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
 | 
			
		||||
#
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2013-03-12 04:08+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"
 | 
			
		||||
"Language: \n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
"Content-Type: text/plain; charset=UTF-8\n"
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:47
 | 
			
		||||
msgid "Additional information here..."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.forms.js:53
 | 
			
		||||
msgid "Filter"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.instances.js:28
 | 
			
		||||
msgid "There was a problem communicating with the server, please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:125
 | 
			
		||||
msgid "There was an error submitting the form. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:159 static/horizon/js/horizon.tabs.js:9
 | 
			
		||||
msgid "Loading"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.modals.js:178
 | 
			
		||||
msgid "An error occurred. Please try again."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:47
 | 
			
		||||
msgid "An error occurred while updating."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:145
 | 
			
		||||
msgid "You have selected "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:158
 | 
			
		||||
msgid "Confirm "
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:159
 | 
			
		||||
msgid "Please confirm your selection. This action cannot be undone."
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:173
 | 
			
		||||
msgid "Working"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.tables.js:216
 | 
			
		||||
#, c-format
 | 
			
		||||
msgid "Displaying %s item"
 | 
			
		||||
msgid_plural "Displaying %s items"
 | 
			
		||||
msgstr[0] ""
 | 
			
		||||
msgstr[1] ""
 | 
			
		||||
 | 
			
		||||
#: static/horizon/js/horizon.users.js:18
 | 
			
		||||
msgid "Passwords do not match."
 | 
			
		||||
msgstr ""
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user