2015-02-24

Kotti CMS - how to store arbitrary data with annotations

With Kotti CMS you can extend existing types inheriting from a base class (eg: Document) and obtain another type of object (eg: MyDocument) with new fields, new workflows, custom views, custom addability conditions, etc.

But sometimes you may want to add a custom field to one or more resources, without having to create a new type. For example you might want to add a colour attribute to all existing Document objects, let's imagine a simple select widget with few colours that will be used for adding a class depending on the choosen colour.

By default Kotti is shipped with an annotations column that can be used to store arbitrary data in a nested dictionary.

You can store arbitrary data in the nested dictionary with a syntax similar to the following one:
context.annotations['SOMEKEY'] = VALUE
and read annotations with:
context.annotations
All you need to do is overriding the add and edit form of your target class. With Pyramid is quite easy to extending an existing application and override views, assets, routes, etc. See http://docs.pylonsproject.org/docs/pyramid/en/latest/narr/extending.html for further info.

Here you can see one possible implementation:
from pyramid.view import view_config
import colander
from deform.widget import SelectWidget
from kotti_actions.views.edit.actions.link import (
    LinkActionAddForm as OriginalLinkActionAddForm,
    LinkActionEditForm as OriginalLinkActionEditForm,
    )
from kotti_actions.resources import (
    LinkAction
    )
...
        colours = [
            ('', 'Select'),
            ('red', 'Red'),
            ('brown', 'Brown'),
            ('beige', 'Beige'),
            ('blue', 'Blue'),
            ]

def add_colour(schema):
    schema['colour'] = colander.SchemaNode(
        colander.String(),
        title=_('Colour'),
        widget=SelectWidget(values=colours),
        missing=u"",
        )

@view_config(name=LinkAction.type_info.add_view, permission='add',
             renderer='kotti:templates/edit/node.pt')
class LinkActionAddForm(OriginalLinkActionAddForm):
    """ Form to add a new instance of CustomContent. """

    def schema_factory(self):
        schema = super(LinkActionAddForm, self).schema_factory()
        add_colour(schema)
        return schema

    def add(self, **appstruct):
        colour = u''
        try:
            colour = appstruct.pop('colour')
        except KeyError:
            pass
        obj = super(LinkActionAddForm, self).add(**appstruct)

        obj.annotations['colour'] = colour
        return obj


@view_config(name='edit', context=LinkAction, permission='edit',
             renderer='kotti:templates/edit/node.pt')
class LinkActionEditForm(OriginalLinkActionEditForm):
    """ Form to edit existing calendars. """

    def schema_factory(self):
        schema = super(LinkActionEditForm, self).schema_factory()
        add_colour(schema)
        return schema

    def before(self, form):
        super(LinkActionEditForm, self).before(form)
        colour = self.context.annotations.get('colour')
        if colour:
            form.appstruct.update({'colour': colour})

    def edit(self, **appstruct):
        super(LinkActionEditForm, self).edit(**appstruct)
        self.context.annotations['colour'] = appstruct['colour']

Now our LinkAction add and edit form will have an additional select with our colours.

All posts about Kotti

All Kotti posts published by @davidemoro:


2015-02-11

Python mock library for ninja testing

If you are going to write unit tests with Python you should consider this library: Python mock (https://pypi.python.org/pypi/mock).

Powerful, elegant, easy, documented (http://www.voidspace.org.uk/python/mock/)...
and standard: mock is now part of the Python standard library, available as unittest.mock in Python 3.3 onwards.

Simple example

Let's suppose you have an existing validator function based on a dbsession import used for querying a relational database. If you are going to write unit tests, you should focus on units without involving real database connections.

validators.py
from yourpackage import DBSession

def validate_sku(value):
    ...
    courses = DBSession.query(Course).\
        filter(Course.course_sku == value).\
        filter(Course.language == context.language).\
        all()
    # validate data returning a True or False value
    ...

tests/test_validators.py
def test_validator():
    import mock
    with mock.patch('yourpackage.validators.DBSession') as dbsession:
        instance = dbsession
        instance.query().filter().filter().all.return_value = [mock.Mock(id=1)]
        from yourpackage.validators import sku_validator
        assert sku_validator(2) is True

In this case the DBSession call with query, the two filter calls and the final all invocation will produce our mock result (a list of with one mock item, an object with an id attribute).

Brilliant! And this is just one simple example: check out the official documentation for further information:

2015-02-04

Kotti CMS - workflow reference

Yet another blog post about Kotti CMS (http://kotti.pylonsproject.org/): this time I'm going to talk about workflows and security.

Workflows in Kotti are based on repoze.workflow. See http://docs.repoze.org/workflow/ for further information. Basically you can use an xml file (zcml) in order to describe your workflow definition. You can see an example here: https://github.com/Kotti/Kotti/blob/master/kotti/workflow.zcml. A you can see it is quite straightforward adding new states, new transitions, new permissions, etc. You can easily turn your 2-states website workflow into a 3-states website workflow with reviewers or turn Kotti app into an intranet application.

The default workflow definition is loaded from your project .ini file settings (using the kotti.use_workflow settings). The kotti.use_workflow setting's default value is:
kotti.use_workflow = kotti:workflow.zcml
but can change change default workflow for the whole site, register new workflows related to specific content types or disable it as well.

Anyway, if you need to write a Python based CMS-ish application with hierarchical contents, custom content types, workflows, security, global and local ACL (sharing permissions), pluggable and extensible, based on relational databases, developer friendly, with a simple UI, etc... Kotti is your friend!

How to disable the default workflow

Kotti is shipped with a simple workflow implementation based on private and public states. If your particular use case does not require workflows at all, you can disable this feature with a non true value. For example:
kotti.use_workflow = 0

How to override the Kotti's default workflow for all content types

The default workflow is quite useful for websites, but sometimes you need something of different. Just change your workflow setting and point to your zcml file:
kotti.use_workflow = kotti_yourplugin:workflow.zcml
The simplest way to deal with workflow definitions is:
  • create a copy of the default workflow definition
  • customize it (change permissions, add new states, permissions, transitions, initial state and so on)
If your site already has content and you configure it use a workflow for the first time, or you use a different workflow than the one you used before, run the kotti-reset-workflow command to reset all your content's workflow.

How to enable the custom workflow for images and files

Images and files are not associated with the default workflow. If you need a workflow for these items you need to attach the IDefaultWorkflow marker interface.

You can add the following lines in your includeme function:
from zope.interface import implementer
from kotti.interfaces import IDefaultWorkflow
from kotti.resources import File
from kotti.resources import Image
...


def includeme(config):
    ...
    # enable workflow for images and files
    implementer(IDefaultWorkflow)(Image)
    implementer(IDefaultWorkflow)(File)
    ...

How to assign a different workflow to a content type

[UPDATE 20150604:
We are going to use the default workflow for standard content types and a custom workflow for content providing the IBoxWorkflow marker interface. The custom workflow is configurable via .ini configuration files.
Note well: the elector, the config.begin/config.commit and the load_zcml can be omitted. I'll update this section soon.

UPDATE 20150606:
Confirmed: things can be done in a simpler way! So no load_zcml, no config.begin/config.commit, no elector.
See the following video:
]

In this kind of situation you want to use the default workflow for all your types and a different workflow implementation for a particular content type.

You'll need to:
  • create the new workflow definition, with a workflow elector
  • write an elector function that will returns True or False depending if the workflow should be applied (otherwise will win the default default workflow, or better, the first matching workflow without an elector)
  • load manually your zcml file in your includeme function
.ini file (optional)
kotti_boxes.use_workflow = kotti_boxes:workflow.zcml
__init__.py
from pyramid.i18n import TranslationStringFactory
from kotti import FALSE_VALUES


def includeme(config):
    ...
    workflow = config.registry.settings.get('kotti_boxes.use_workflow', None)
    if workflow and workflow.lower() not in FALSE_VALUES:
        config.begin()

        config.hook_zca()
        config.include('pyramid_zcml')
        config.load_zcml(workflow)
        config.commit()

    ...
workflow.py
From the repoze.workflow documentation: """A workflow is unique in a system using multiple workflows if the combination of its type, its content type, its elector, and its state_attr are different than the combination of those attributes configured in any other workflow."""
Depending on how specific is your combination you may need to implement an elector (a function that returns True or False for a given context).
from kotti_boxes.interfaces import IBoxWorkflow


def elector(context):
    return IBoxWorkflow.providedBy(context)
workflow.zcml
<configure xmlns="http://namespaces.repoze.org/bfg"
           xmlns:i18n="http://xml.zope.org/namespaces/i18n"
           i18n:domain="Kotti">
  <include package="repoze.workflow" file="meta.zcml"/>

  <workflow
      type="security"
      name="simple"
      state_attr="state"
      initial_state="private"
      content_types="kotti_boxes.interfaces.IBoxWorkflow"
      elector='kotti_boxes.workflow.elector'
      permission_checker="pyramid.security.has_permission"
      >
    <state name="private" callback="kotti.workflow.workflow_callback">
      <key name="title" value="_(u'Private')" />
      <key name="order" value="1" />
      <key name="inherit" value="0" />
      <key name="system.Everyone" value="" />
      <key name="role:viewer" value="viewbox view" />
      <key name="role:editor" value="viewbox view add edit delete state_change" />
      <key name="role:owner" value="viewbox view add edit delete manage state_change" />
    </state>
    ...

  <transition
      name="private_to_public"
      from_state="private"
      to_state="public"
      permission="state_change" />
  ...

  </workflow>
</configure>

All posts about Kotti

2015-02-03

Kotti CMS - how to create a new content type with an image

If you want to create a new content type based on an existing one with Kotti you need to write few lines of code and zero html for the add and edit views: it is very simple (browse Kotti's resources.py and views code).


Basically you have to extend the existing content type shipped with Kotti and add your custom fields.

But let's suppose you need a new content type named ImageWithLink with the following fields:
  • title
  • description
  • image
  • link
In this case the implementation is more verbose compared to extend another content type (like the Document, but it is still an easy job).

resources.py
from zope.interface import implements
from kotti.resources import Image
from kotti.interfaces import IImage
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Unicode


class ImageWithLink(Image):
    implements(IImage)

    id = Column(Integer, ForeignKey('images.id'), primary_key=True)
    link = Column(Unicode(1000))

    type_info = Image.type_info.copy(
        name=u'ImageWithLink',
        title=u'ImageWithLink',
        add_view=u'add_image_link',
        addable_to=['Document'],
        )

    def __init__(self, link=u"", **kwargs):
        super(ImageWithLink, self).__init__(**kwargs)
        self.link = link 
The code is quite self-explaining: you create a new ImageWithLink class that inherits from Image. You only need to add your custom field named link and you initialize the link in the __init__ code after calling the super method.

views/content.py
import colander
from deform import FileData
from deform.widget import FileUploadWidget
from kotti.views.edit import ContentSchema
from kotti.views.edit.content import ImageEditForm
from kotti.views.edit.content import ImageAddForm
from kotti.views.form import validate_file_size_limit
from kotti.views.form import FileUploadTempStore
from kotti.views.form import AddFormView
from pyramid.view import view_config
from kotti_yourplugin import _
from kotti_yourplugin.resources import ImageWithLink
from kotti_yourplugin.validators import link_validator


def ImageWithLinkSchema(tmpstore):
    """ File schema with no set title missing binding """
    class ImageWithLinkSchema(ContentSchema):
        file = colander.SchemaNode(
            FileData(),
            title=_(u'File'),
            widget=FileUploadWidget(tmpstore),
            validator=validate_file_size_limit,
            )
        link = colander.SchemaNode(
            colander.String(),
            title=_('Link'),
            validator=link_validator,
            missing=u'',
            )

    def after_bind(node, kw):
        del node['tags']

    return ImageWithLinkSchema(after_bind=after_bind)


@view_config(name='edit', permission='edit',
             renderer='kotti:templates/edit/node.pt')
class ImageWithLinkEditForm(ImageEditForm):
    def schema_factory(self):
        tmpstore = FileUploadTempStore(self.request)
        return ImageWithLinkSchema(tmpstore)


@view_config(name=ImageWithLink.type_info.add_view, permission='add',
             renderer='kotti:templates/edit/node.pt')
class ImageWithLinkAddForm(ImageAddForm):
    item_type = _(u"Banner Box")
    item_class = ImageWithLink

    def schema_factory(self):
        tmpstore = FileUploadTempStore(self.request)
        return ImageWithLinkSchema(tmpstore)

    def save_success(self, appstruct):
        # override this method (no filename as title
        # like images)
        return AddFormView.save_success(self, appstruct)

    def add(self, **appstruct):
        # override (no tags in our form)
        buf = appstruct['file']['fp'].read()
        filename = appstruct['file']['filename']
        return self.item_class(
            title=appstruct['title'] or filename,
            description=appstruct['description'],
            data=buf,
            filename=filename,
            mimetype=appstruct['file']['mimetype'],
            size=len(buf),
            )
Here the code is more complex. There is a dynamic schema definition with the Kotti's temp store implementation. Both the add and the edit form refer to this schema, with some overrides because our object does not behave like files or images.

validators.py
UPDATE 20150211: no need to write this validator. Use the url validator provided by colander instead (colander.url). Anyway you can use all the builtin colander validators or write your own validators.

import re
import colander
from kotti_yourplugin import _


VALID_PROTOCOLS = ('http',)
URL_REGEXP = r'(%s)s?://[^\s\r\n]+' % '|'.join(VALID_PROTOCOLS)


def link_validator(node, value):
    """ Raise a colander.Invalid exception if the provided url
        is not valid
    """
    def raise_invalid_url(node, value):
        raise colander.Invalid(
            node, _(u"You must provide a valid url."))
    if value:
        if not re.match(URL_REGEXP, value):
            raise_invalid_url(node, value)
Here you can see an example of link validator based on a regular expression. This validator decorates our link field of the ImageWithLink schema.

Obviously you need to add in your kotti_configure method your ImageWithLink in the kotti.available_types settings.

__init__.py
def kotti_configure(settings):
    settings['pyramid.includes'] += ' kotti_yourplugin'
    settings['kotti.available_types'] += ' kotti_yourplugin.resources.ImageWithLink'

and enable your configurator in your .ini file:
kotti.configurators =     mip_course.kotti_configure

And what about the default view of your content types? If you visit an ImageWithLink box it will behave like an image: it inherits the default view of the image (you should customize it adding the link on the image, very simple: not showed in this blog post), no need to deal with the image resize machinery, etc.

As you can see, Kotti is a flexible solution if you need a simple but powerful CMS solution based on Python, Pyramid and SQLAlchemy. You may consider it as a simple framework (but easy to understand, don't be scared by the word framework. It is really developer friendly). If you are curious about how to manage contents with Kotti you may play with the demo online: http://kottidemo.danielnouri.org/ (admin - qwerty).

All posts about Kotti

All Kotti posts published by @davidemoro:


2015-01-23

Kotti - avoid types addable in content root

With Kotti CMS (http://kotti.pylonsproject.org/) you don't have to fight against the framework: after one or two days you'll love it and you will be productive.

You can add new content types mapped on database tables, extend existing ones, add one or more object actions, easy building of add and edit views without having to touch any html file.

Kotti is shipped with the pytest framework and I love it! The tests setup is very easy and you can mock or initialize your reusable fixtures with a dependency injection technique.

If your customer wants to use Windows, no problem:

How to prevent your content types to be added in content root

This blog post will explain how to prevent your content type to be added in the content root but only in Document types (they behave like folderish items too). What's the matter? The root itself is a Document.

My solution was similar to the following one, but a bit different:

# resources.py

from kotti.resources import TypeInfo
from kotti.resources import get_root
from kotti.resources import Content
...

class YourContentTypeInfo(TypeInfo):

    def addable(self, context, request):
        root = get_root()
        if context == root:
            return False
        return super(YourContentTypeInfo, self).addable(context, request)

yourcontent_type_info_data = Content.type_info.copy(
    name=u'YourContent',
    title=_(u'YourContent'),
    add_view=u'add_yourcontent',
    addable_to=[u'Document'],
    ).__dict__.copy()
yourcontent_type_info = YourContentTypeInfo(**course_type_info_data)

class YourContent(Content):
    """ A yourcontent type. """

    implements(IDefaultWorkflow)

    id = Column(Integer, ForeignKey('contents.id'), primary_key=True)
    ...

    type_info = yourcontent_type_info
I tried to inherit all the default options and actions from the default Content's type info. This way you'll inherit all the backend menu actions.

Done!

Feedback

After using Kotti for a while I can tell that the feedback is absolutely positive. It is the right choice when you don't need a much more complex system like Plone. So join the Python, Pyramid and Kotti community and say love to Kotti!
https://twitter.com/davidemoro/status/558188730222383104

All posts about Kotti

All Kotti posts published by @davidemoro:


2015-01-19

How to install Kotti CMS on Windows

Yes, as expected, you can install Kotti CMS also on Windows if you have this constraint!

What is Kotti

From the official doc:

"""A high-level, Pythonic web application framework based on Pyramid and SQLAlchemy. It includes an extensible Content Management System called the Kotti CMS.

Kotti is most useful when you are developing applications that:
  • have complex security requirements
  • use workflows, and/or
  • work with hierarchical data
"""

It is developer friendly and with a good user interface. You can easily extend it, develop new features or install one of the available third party modules (search for Kotti on https://pypi.python.org/pypi if you want to browse existing modules ready to be used). Heavily inspired by Plone (http://plone.org).
If you want to evaluate Kotti you can install it locally (no database installation is required, you can use SQLlite during evaluation or development).
Otherwise if you are particular lazy there is a working demo online with admin / qwerty administrator credentials: 

Prerequisites

  • python (tested with python 2.7.9 but it should work also on newer versions)
  • Microsoft Visual C++ 9.0 available on the following url http://aka.ms/vcpython27 (needed for an issue with bcrypt)
  • virtualenv (suggested)

Installation steps

Once you have installed python from http://www.python.org you can start installing Kotti. I assume in this article that your Python installation path is C:\Python27.
Now create a new folder (it doesn't matter the name, in this article my folder name is just kotti):
> mkdir kotti
> cd kotti
Install virtualenv and create a new isolated python environment in your kotti dir:
> C:\Python27\Scripts\pip.exe install virtualenv> C:\Python27\Scripts\virtualenv.exe --no-site-packages .
Install Kotti and its requirements:
> Scripts\pip.exe install -r https://raw.github.com/Kotti/Kotti/stable/requirements.txt
> Scripts\pip.exe install Kotti

Put inside your kotti dir the app.ini file downloaded from:
Runs Kotti:
Scripts\pserve.exe app.ini
Starting server in PID 2452
serving on http://127.0.0.1:5000
Done!

Update 20150219: if you want to install Kotti as a standard Windows service see this tutorial: http://pyramid-cookbook.readthedocs.org/en/latest/deployment/windows.html.

Troubleshooting (tested on Windows Vista)

If Microsoft Visual C++ Compiler for Python 2.7 is not installed on your environment you'll get an error during the requirements installation phase (only on Windows):
> Scripts\pip.exe install -r https://raw.githubusercontent.co
m/Kotti/Kotti/stable/requirements.txt
....
  Running setup.py install for py-bcrypt
    building 'bcrypt._bcrypt' extension
    error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat).
Get it from http://aka.ms/vcpython27
    Complete output from command C:\Users\dmoro\kotti\Scripts\python.exe -c "imp
ort setuptools, tokenize;__file__='c:\\users\\dmoro\\appdata\\local\\temp\\pip-b
uild-mact2r\\py-bcrypt\\setup.py';exec(compile(getattr(tokenize, 'open', open)(_
_file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record c:\u
sers\dmoro\appdata\local\temp\pip-wcmy6c-record\install-record.txt --single-vers
ion-externally-managed --compile --install-headers C:\Users\dmoro\kotti\include\
site\python2.7:
    running install

    running build

    running build_py

    creating build

    creating build\lib.win-amd64-2.7

    creating build\lib.win-amd64-2.7\bcrypt

    copying bcrypt\__init__.py -> build\lib.win-amd64-2.7\bcrypt

    running build_ext

    building 'bcrypt._bcrypt' extension

    error: Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat).
Get it from http://aka.ms/vcpython27
You just need to install this requirement and all will work fine.

Troubleshooting 2 (tested on Windows 2008 R2 Server - updated 20150219)

You might experience other compilation errors on Windows due to different compiler versions, role management tool configuration, missing DLLs, environment variables (vcvars32.bat), missing header files, etc. The same C code that compiles fine on a Windows machine, on a different version of Windows could produce a compilation error (compiling under Windows is a pain).

Anyway the following links helped me a lot a install py-bcrypt under Windows 2008 R2 Server with Visual Studio 2008 Express (free version downloadable from http://go.microsoft.com/?linkid=7729279):

Links

Screenshots

Kotti's front page (from the public demo online):

Kotti's folder contents (from the public demo online), requires authentication:

All posts about Kotti

All Kotti posts published by @davidemoro:



2014-11-25

Dr. Jekyll and Mr. GitHub Pages

Time ago I started using the GitHub Pages service just for fun:
With GitHub Pages you can write documentation, create a landing page for your account or organization and create unlimited project sites for you and your projects.

Websites, blogs, landing pages, live demos.

Things are hosted directly from your GitHub repo. So just edit, push and your changes are live (and under version control and easy collaboration with other team members).

You can generate a site using one of the pre-built themes or create a site from scratch.

Who is using GitHub Pages?
We'll cover these topics in this article:
  • type of sites you can build with GitHub Pages
    • user or organization site
    • project site
  • site generation methods
    • pre-built themes
    • from scratch
  • advanced blogging tools (with Jekyll)

User or organization site from scratch (master)

You can create your personal page or organization site for free.

First: create a new repository named username.github.io, where username is your username (or organization name) on GitHub.

Then clone your repo:
$ git clone https://github.com/username/username.github.io
$ cd username.github.io
Create a demo hello world page:
$ echo "Hello World" > index.html
Push:
$ git add --all
$ git commit -m "Initial commit"
$ git push
Visit your page (you'll have to wait a bit the very first time you update your site):
  • http://username.github.io

Project site (gh-pages branch)

For Project sites, you have the option to generate a site with one of the available pre-built themes, or to create a site from scratch.

Generate a site (pre-built themes)

Go to the settings panel of you repository and click on the Automatic Page Generator.

You can use the editor to add content and then pick a theme and publish!

Start from scratch

Follow this guide:

Jekyll

GitHub pages can be used in conjunction with Jekyll http://jekyllrb.com/.

What you can do with Jekyll:
"""Using Jekyll, you can blog using beautiful Markdown syntax, and without having to deal with any databases.

One of Jekyll’s best aspects is that it is “blog aware”. What does this mean, exactly? Well, simply put, it means that blogging is baked into Jekyll’s functionality. If you write articles and publish them online, this means that you can publish and maintain a blog simply by managing a folder of text-files on your computer. Compared to the hassle of configuring and maintaining databases and web-based CMS systems, this will be a welcome change!"""
Here you can find some useful resources about Jekyll and GitHub Pages:
Prerequisites: Ruby. Your Ruby version should begin with 1.9.3 or 2.0.0.

User or organization site

Bootstrap a new dir name USER_OR_ORGANIZATION.github.io: 
$ jekyll new USER_OR_ORGANIZATION.github.io
$ cd USER_OR_ORGANIZATION.github.io
Basically you'll have to install Jekyll and Bundle as suggested on the GitHub official doc. Create a Gemfile file with this content:
source 'https://rubygems.org'
gem 'github-pages'
Check your url and baseurl options of your _config.yml file.
_config.yml for a project/repository site:
        ...
        baseurl: "/REPOSITORY" # the subpath of your site, e.g. /blog/
        url: "http://USER_OR_ORGANIZATION.github.io" # the base hostname & protocol for your site

Invoke Jekyll with Bundler:
$ bundle install
$ bundle exec jekyll build
The .gitignore file is already generated.

Now you can create the repo online on github and push your contents (.gitignore file already generated). Before pushing it is suggested to run Jekyll locally:
$ bundle exec jekyll serve
Result:
Now you can add new posts, change your page title, etc. See the _config.yml dir, the _posts dir and the official documentation online.

Now you can push your changes and they will display online.

Repo/Project site (with Jekyll)

You should create a gh-pages branch of your repository.

Follow this guide:
but instead of putting plain html files, initialize your branch with Jekyll (with bundle exec jekyll new .).

And then check your _config.yml. The user/organization site requires a different setup:
        ...
        baseurl: "" # the subpath of your site, e.g. /blog/
        baseurl: "/REPOSITORY" # the subpath of your site, e.g. /blog/
        url: "http://USER_OR_ORGANIZATION.github.io" # the base hostname & protocol for your site

Now you can build things and upload to GitHub. Results will displayed on http://USER_OR_ORGANIZATION.github.io/REPOSITORY.

Jekyll troubleshooting

Error 1 (LoadError):
/var/lib/gems/1.9.1/gems/jekyll-2.5.1/bin/jekyll:21:in `block in <top (required)>': cannot load such file -- jekyll/version (LoadError)
Solution (see https://github.com/jekyll/jekyll/issues/3084):
$ bundle exec jekyll COMMAND ("serve" or "new .")
Error 2 (Gemfile does not exist and directory is not empty)
I got two strange errors initializing an empty dir with Jekyll with the "bundle exec jekyll new ." command. Something like "error: Gemfile does not exist". Ok, let's create a Gemfile and "error: directory is not empty". If worked for me "bundle exec jekyll new USER_OR_ORGANIZATION.github.io"