Exemple #1
0
    def __init__(self, prompt, datastore, theme, patterns_map):
        self.indentation_level = "│  "
        self.patterns_map = patterns_map
        self.datastore = datastore
        # Notify wich thread is processed
        if prompt != "":
            notify("├─ " + prompt)

        self.forbidden = patterns_map.non_contextual_entries_keys
        self.entries_per_page = int(
            datastore.blog_configuration["entries_per_pages"])
        self.disable_threads = datastore.disable_threads

        # Setup useful data
        self.theme = theme
        self.footer = deepcopy(self.theme.footer)
        self.header = deepcopy(self.theme.header)
        self.entry = deepcopy(self.theme.entry)
        self.context_header = "header.html"
        self.context_footer = "footer.html"
        self.content_type = "html"
        self.column_opening = '<div id="__VENC_COLUMN_{0}__" class="__VENC_COLUMN__">'
        self.column_closing = "</div>"
        self.columns_number = self.datastore.blog_configuration["columns"]
        # Setup pattern processor
        self.processor = Processor()
        for pattern_name in patterns_map.contextual["functions"].keys():
            self.processor.set_function(
                pattern_name,
                patterns_map.contextual["functions"][pattern_name])

        for pattern_name in patterns_map.contextual["names"].keys():
            self.processor.set_function(
                pattern_name,
                getattr(self, patterns_map.contextual["names"][pattern_name]))
Exemple #2
0
def setup_pattern_processor(pattern_map):
    cpu_threads = len(datastore.cpu_threads_requested_entry)

    processor = Processor(cpu_threads)
    for pattern_name in pattern_map.non_contextual["entries"].keys():
        processor.set_function(
            pattern_name, pattern_map.non_contextual["entries"][pattern_name])

    for pattern_name in pattern_map.non_contextual["blog"].keys():
        processor.set_function(
            pattern_name, pattern_map.non_contextual["blog"][pattern_name])

    for pattern_name in pattern_map.non_contextual["extra"].keys():
        processor.set_function(
            pattern_name, pattern_map.non_contextual["extra"][pattern_name])

    for pattern_name in pattern_map.contextual["names"].keys():
        processor.blacklist.append(pattern_name)

    for pattern_name in pattern_map.contextual["functions"].keys():
        processor.blacklist.append(pattern_name)

    for pattern_name in pattern_map.keep_appart_from_markup:
        processor.keep_appart_from_markup.append(pattern_name)

    processor.blacklist.append("Escape")
    return processor
Exemple #3
0
    def __init__(self, prompt, datastore, theme, patterns_map):
        self.indentation_level = "│  "
        self.patterns_map = patterns_map
        self.datastore = datastore
        # Notify wich thread is processed
        if prompt != "":
            notify("├─ "+prompt)

        self.forbidden = patterns_map.non_contextual_entries_keys
        self.entries_per_page = int(datastore.blog_configuration["entries_per_pages"])
        self.disable_threads = datastore.disable_threads

        # Setup useful data
        self.theme = theme
        self.footer = deepcopy(self.theme.footer)
        self.header = deepcopy(self.theme.header)
        self.entry = deepcopy(self.theme.entry)
        self.context_header = "header.html"
        self.context_footer = "footer.html"
        self.content_type = "html"
        self.column_opening = '<div id="__VENC_COLUMN_{0}__" class="__VENC_COLUMN__">'
        self.column_closing = "</div>"
        self.columns_number = self.datastore.blog_configuration["columns"]
        # Setup pattern processor
        self.processor = Processor()
        for pattern_name in patterns_map.contextual["functions"].keys():
            self.processor.set_function(pattern_name, patterns_map.contextual["functions"][pattern_name])
                
        for pattern_name in patterns_map.contextual["names"].keys():
            self.processor.set_function(pattern_name, getattr(self, patterns_map.contextual["names"][pattern_name]))
Exemple #4
0
def setup_pattern_processor(pattern_map):
    processor = Processor()
    for pattern_name in pattern_map.non_contextual["entries"].keys():
        processor.set_function(pattern_name, pattern_map.non_contextual["entries"][pattern_name])
    
    for pattern_name in pattern_map.non_contextual["blog"].keys():
        processor.set_function(pattern_name, pattern_map.non_contextual["blog"][pattern_name])
        
    for pattern_name in pattern_map.non_contextual["extra"].keys():
        processor.set_function(pattern_name, pattern_map.non_contextual["extra"][pattern_name])
    
    for pattern_name in pattern_map.contextual["names"].keys():
        processor.blacklist.append(pattern_name)
        
    for pattern_name in pattern_map.contextual["functions"].keys():
        processor.blacklist.append(pattern_name)
        
    for pattern_name in pattern_map.keep_appart_from_markup:
        processor.keep_appart_from_markup.append(pattern_name)

    processor.blacklist.append("Escape")
    return processor
Exemple #5
0
def setup_pattern_processor(pattern_map):
    processor = Processor()
    for pattern_name in pattern_map.non_contextual["entries"].keys():
        processor.set_function(pattern_name, pattern_map.non_contextual["entries"][pattern_name])
    
    for pattern_name in pattern_map.non_contextual["blog"].keys():
        processor.set_function(pattern_name, pattern_map.non_contextual["blog"][pattern_name])
        
    for pattern_name in pattern_map.non_contextual["extra"].keys():
        processor.set_function(pattern_name, pattern_map.non_contextual["extra"][pattern_name])
    
    for pattern_name in pattern_map.contextual["names"].keys():
        processor.blacklist.append(pattern_name)
        
    for pattern_name in pattern_map.contextual["functions"].keys():
        processor.blacklist.append(pattern_name)
        
    for pattern_name in pattern_map.keep_appart_from_markup:
        processor.keep_appart_from_markup.append(pattern_name)

    processor.blacklist.append("Escape")
    return processor
    except:
        raise PatternMissingArguments()

    return a.upper()

def trigger_generic_message_exception(argv):
    raise GenericMessage("lol it will never work")

def trigger_pattern_invalid_argument_exception(argv):
    raise PatternInvalidArgument("some field", "some value", "some message")

def trigger_unknown_contextual_exception(argv):
    raise UnknownContextual()

processor = Processor()
processor.debug = True
processor.set_function("add", add)
processor.set_function("mul", mul)
processor.set_function("greater", greater)
processor.set_function("upper", upper)
processor.set_function("trigger_generic_message_exception", trigger_generic_message_exception)
processor.set_function("trigger_pattern_invalid_argument_exception", trigger_pattern_invalid_argument_exception)
processor.set_function("trigger_unknown_contextual_exception", trigger_unknown_contextual_exception)
processor.blacklist.append("blacklisted")

def test_pattern_processor(args, test_name):
    input_value, process_escapes = args
    ps = ProcessedString(input_value, test_name, process_escapes)
    processor.process(ps)
    return ps.string
Exemple #7
0
class Thread:
    def __init__(self, prompt, datastore, theme, patterns_map):
        self.indentation_level = "│  "
        self.patterns_map = patterns_map
        self.datastore = datastore
        # Notify wich thread is processed
        if prompt != "":
            notify("├─ " + prompt)

        self.forbidden = patterns_map.non_contextual_entries_keys
        self.entries_per_page = int(
            datastore.blog_configuration["entries_per_pages"])
        self.disable_threads = datastore.disable_threads

        # Setup useful data
        self.theme = theme
        self.footer = deepcopy(self.theme.footer)
        self.header = deepcopy(self.theme.header)
        self.entry = deepcopy(self.theme.entry)
        self.context_header = "header.html"
        self.context_footer = "footer.html"
        self.content_type = "html"
        self.column_opening = '<div id="__VENC_COLUMN_{0}__" class="__VENC_COLUMN__">'
        self.column_closing = "</div>"
        self.columns_number = self.datastore.blog_configuration["columns"]
        # Setup pattern processor
        self.processor = Processor()
        for pattern_name in patterns_map.contextual["functions"].keys():
            self.processor.set_function(
                pattern_name,
                patterns_map.contextual["functions"][pattern_name])

        for pattern_name in patterns_map.contextual["names"].keys():
            self.processor.set_function(
                pattern_name,
                getattr(self, patterns_map.contextual["names"][pattern_name]))

    def return_page_around(self, string, params):
        return string.format(**params)

    # Must be called in child class
    def get_relative_location(self, argv):
        return self.export_path[5:]

    # Must be called in child class
    def organize_entries(self, entries):
        self.pages = list()
        for i in range(0, ceil(len(entries) / self.entries_per_page)):
            self.pages.append(entries[i * self.entries_per_page:(i + 1) *
                                      self.entries_per_page])

        self.pages_count = len(self.pages)

    # Must be called in child class
    def get_next_page(self, argv):
        if self.current_page < self.pages_count - 1:
            params = {
                "page_number": str(self.current_page + 1),
                "entry_id": '',
                "entry_title": '',
                "path": ''
            }

            if self.in_thread:
                params["path"] = self.filename.format(**params)

            else:
                try:
                    params["path"] = self.current_entry.next_entry.url
                    params["entry_id"] = self.current_entry.next_entry.id
                    params["entry_title"] = self.current_entry.next_entry.title

                except AttributeError:
                    pass

            return argv[0].format(**params)

        else:
            return str()

    # Must be called in child class
    def get_previous_page(self, argv):
        if self.current_page > 0:
            params = {
                "page_number":
                str(self.current_page -
                    1) if self.current_page - 1 != 0 else '',
                "entry_id":
                '',
                "entry_title":
                '',
                "path":
                ''
            }

            if self.in_thread:
                params["path"] = self.filename.format(**params)

            else:
                try:
                    params["entry_id"] = self.current_entry.previous_entry.id
                    params[
                        "entry_title"] = self.current_entry.previous_entry.title
                    params["path"] = self.current_entry.previous_entry.url
                except AttributeError:
                    pass

            return argv[0].format(**params)

        else:
            return str()

    # Must be called in child class
    def for_pages(self, argv):
        list_lenght = int(argv[0])
        string = argv[1]
        separator = argv[2]

        if self.pages_count <= 1:
            return str()

        output = str()
        page_number = 0
        for page in self.pages:
            if (not page_number < self.current_page - list_lenght) and (
                    not page_number > self.current_page + list_lenght):
                try:
                    output += string.format(
                        **{
                            "entry_id":
                            '',
                            "entry_title":
                            '',
                            "page_number":
                            str(page_number),
                            "path":
                            self.filename.format(
                                **{
                                    "page_number": (str() if page_number ==
                                                    0 else page_number)
                                })
                        }) + separator
                except KeyError as e:
                    print(e)
                    raise PatternInvalidArgument(name="string", value=string)

            page_number += 1

        return output[:-len(separator)]

    def JSONLD(self, argv):
        return ''

    def if_in_first_page(self, argv):
        if self.current_page == 0:
            return argv[0].strip()

        else:
            return argv[1].strip()

    def if_in_last_page(self, argv):
        if self.current_page == len(self.pages) - 1:
            return argv[0].strip()

        else:
            return argv[1].strip()

    def if_in_entry_id(self, argv):
        return argv[2].strip()

    def if_in_categories(self, argv):
        return argv[1].strip()

    def if_in_archives(self, argv):
        return argv[1].strip()

    def if_in_thread(self, argv):
        if self.in_thread:
            return argv[0].strip()

        else:
            return argv[1].strip()

    def format_filename(self, value):
        try:
            if value == 0:
                return self.filename.format(**{'page_number': ''})

            else:
                return self.filename.format(**{'page_number': value})

        except KeyError as e:
            die(messages.variable_error_in_filename.format(str(e)))

    # Overridden in child class (EntriesThread)
    def setup_context(self, entry):
        self.current_entry = entry

    def write_file(self, output, file_id):
        if self.in_thread:
            format_value = file_id

        else:
            format_value = page[0].id

        stream = codecs.open(self.export_path + '/' +
                             self.format_filename(format_value),
                             'w',
                             encoding="utf-8")
        stream.write(output)
        stream.close()

    def pre_iteration(self):
        self.processor.blacklist = self.forbidden
        self.processor.process(self.header, safe_process=True)
        self.output = self.header.string
        self.header.restore()
        self.processor.blacklist = []
        self.columns_counter = 0
        self.columns = ['' for i in range(0, self.columns_number)]

    def post_iteration(self):
        self.columns_counter = 0
        for column in self.columns:
            self.output += self.column_opening.format(
                self.columns_counter) + column + self.column_closing

        self.processor.blacklist = self.forbidden
        self.processor.process(self.footer, safe_process=True)
        self.output += self.footer.string
        self.footer.restore()

        self.write_file(
            self.output.replace(".:GetRelativeOrigin:.", self.relative_origin),
            self.page_number)

        self.page_number += 1
        self.current_page = self.page_number

    def do_iteration(self, entry):
        content_header = getattr(entry, self.content_type + "_wrapper").above
        self.processor.process(content_header, safe_process=True)
        self.columns[self.columns_counter] += content_header.string
        content_header.restore()

        if (entry.html_wrapper.required_content_pattern
                == ".:GetEntryPreview:.") or (
                    entry.html_wrapper.required_content_pattern
                    == ".:PreviewIfInThreadElseContent:." and self.in_thread):
            self.processor.process(entry.preview, safe_process=True)
            self.columns[self.columns_counter] += entry.preview.string
            entry.preview.restore()

        else:
            self.processor.process(entry.content, safe_process=True)
            self.columns[self.columns_counter] += entry.content.string
            entry.content.restore()

        content_footer = getattr(entry, self.content_type + "_wrapper").below
        self.processor.process(content_footer, safe_process=True)
        self.columns[self.columns_counter] += content_footer.string
        content_footer.restore()

        self.columns_counter += 1
        if self.columns_counter >= self.columns_number:
            self.columns_counter = 0

    def iterate_through_pages(self):
        for page in self.pages:
            self.pre_iteration()
            for entry in page:
                self.setup_context(entry)
                self.do_iteration(entry)

            self.post_iteration()

    # Must be called in child class
    def do(self):
        self.current_page = 0
        self.page_number = 0
        if self.pages_count == 0:
            self.processor.process(self.header)
            output = self.header.string

            self.processor.process(self.footer)
            output += self.footer.string
            stream = codecs.open(self.export_path + '/' +
                                 self.format_filename(0),
                                 'w',
                                 encoding="utf-8")
            stream.write(
                output.replace(".:GetRelativeOrigin:.", self.relative_origin))
            stream.close()

        else:
            self.iterate_through_pages()
Exemple #8
0
class Thread:
    def __init__(self, prompt, datastore, theme, patterns_map):
        self.workers_count = len(datastore.cpu_threads_requested_entry)
        self.indentation_level = "│  "
        self.patterns_map = patterns_map
        self.datastore = datastore
        self.enable_jsonld = datastore.blog_configuration["enable_jsonld"]
        self.path_encoding = datastore.blog_configuration["path_encoding"]
        # Notify wich thread is processed
        if prompt != "":
            notify("├─ " + prompt)

        self.forbidden = patterns_map.non_contextual_entries_keys
        self.entries_per_page = int(
            datastore.blog_configuration["entries_per_pages"])
        self.disable_threads = datastore.disable_threads

        # Setup useful data
        self.theme = theme
        self.footer = deepcopy(self.theme.footer)
        self.header = deepcopy(self.theme.header)
        self.entry = deepcopy(self.theme.entry)
        self.context_header = "header.html"
        self.context_footer = "footer.html"
        self.content_type = "html"
        self.column_opening = '<div id="__VENC_COLUMN_{0}__" class="__VENC_COLUMN__">'
        self.column_closing = "</div>"
        self.columns_number = self.datastore.blog_configuration["columns"]
        self.thread_name = ""
        self.rss_feed = None
        self.atom_feed = None
        # Setup pattern processor
        self.processor = Processor(self.workers_count)
        for pattern_name in patterns_map.contextual["functions"].keys():
            self.processor.set_function(
                pattern_name,
                patterns_map.contextual["functions"][pattern_name])

        for pattern_name in patterns_map.contextual["names"].keys():
            self.processor.set_function(
                pattern_name,
                getattr(self, patterns_map.contextual["names"][pattern_name]))

    def path_encode(self, path):
        if self.path_encoding in ["utf-8", '']:
            return quirk_encoding(unidecode.unidecode(path))

        else:
            return path

    def return_page_around(self, string, params):
        try:
            return string.format(**params)

        except KeyError as e:
            raise UnknownContextual(str(e)[1:-1])

    # Must be called in child class
    def get_relative_location(self, cpu_thread_id, argv):
        return self.export_path[5:]

    def get_relative_origin(self, cpu_thread_id, argv):
        return self.relative_origin

    def get_thread_name(self, cpu_thread_id, argv):
        if len(self.thread_name):
            try:
                return argv[0].format(**{"value": self.thread_name})
            except IndexError:
                return self.thread_name

        else:
            try:
                return argv[1]

            except IndexError:
                return ""

    # Must be called in child class
    def organize_entries(self, entries):
        self.pages = list()
        for i in range(0, ceil(len(entries) / self.entries_per_page)):
            self.pages.append(entries[i * self.entries_per_page:(i + 1) *
                                      self.entries_per_page])

        self.pages_count = len(self.pages)

    # Must be called in child class
    def get_next_page(self, cpu_thread_id, argv):
        if self.current_page < self.pages_count - 1:
            params = {
                "page_number": str(self.current_page + 1),
                "entry_id": '',
                "entry_title": '',
                "path": ''
            }

            if self.in_thread:
                params["path"] = self.filename.format(**params)

            else:
                try:
                    params["path"] = self.current_entry.next_entry.url
                    params["entry_id"] = self.current_entry.next_entry.id
                    params["entry_title"] = self.current_entry.next_entry.title

                except AttributeError:
                    pass

            try:
                return argv[0].format(**params)

            except KeyError as e:
                raise UnknownContextual(str(e)[1:-1])

        else:
            return str()

    # Must be called in child class
    def get_previous_page(self, cpu_thread_id, argv):
        if self.current_page > 0:
            params = {
                "page_number":
                str(self.current_page -
                    1) if self.current_page - 1 != 0 else '',
                "entry_id":
                '',
                "entry_title":
                '',
                "path":
                ''
            }

            if self.in_thread:
                params["path"] = self.filename.format(**params)

            else:
                try:
                    params["entry_id"] = self.current_entry.previous_entry.id
                    params[
                        "entry_title"] = self.current_entry.previous_entry.title
                    params["path"] = self.current_entry.previous_entry.url
                except AttributeError:
                    pass

            try:
                return argv[0].format(**params)

            except KeyError as e:
                raise UnknownContextual(str(e)[1:-1])

        else:
            return str()

    # Must be called in child class
    def for_pages(self, cpu_thread_id, argv):
        list_lenght = int(argv[0])
        string = argv[1]
        separator = argv[2]

        if self.pages_count <= 1:
            return str()

        output = str()
        page_number = 0
        for page in self.pages:
            if (not page_number < self.current_page - list_lenght) and (
                    not page_number > self.current_page + list_lenght):
                try:
                    output += string.format(
                        **{
                            "entry_id": '',
                            "entry_title": '',
                            "page_number": str(page_number),
                            "path": self.format_filename(page_number)
                        }) + separator

                except KeyError as e:
                    raise UnknownContextual(str(e)[1:-1])

            page_number += 1

        return output[:-len(separator)]

    def JSONLD(self, cpu_thread_id, argv):
        return ''

    def if_pages(self, cpu_thread_id, argv):
        if self.pages_count > 1:
            return argv[0].strip()

        elif len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_first_page(self, cpu_thread_id, argv):
        if self.current_page == 0:
            return argv[0].strip()

        elif len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_last_page(self, cpu_thread_id, argv):
        if self.current_page == len(self.pages) - 1:
            return argv[0].strip()

        elif len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_entry_id(self, cpu_thread_id, argv):
        if len(argv) >= 3:
            return argv[2].strip()

        else:
            return ''

    def if_in_main_thread(self, cpu_thread_id, argv):
        if len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_categories(self, cpu_thread_id, argv):
        if len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_archives(self, cpu_thread_id, argv):
        if len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_thread(self, cpu_thread_id, argv):
        if self.in_thread:
            return argv[0].strip()

        elif len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_feed(self, cpu_thread_id, argv):
        if len(argv) >= 2:
            return argv[1].strip()

        else:
            return ''

    def if_in_thread_and_has_feeds(self, cpu_thread_id, argv):
        return argv[0] if self.thread_has_feeds else (
            "" if len(argv) <= 1 else argv[1])

    def format_filename(self, value):
        try:
            if value == 0:
                return self.path_encode(
                    self.filename.format(**{'page_number': ''}))

            else:
                return self.path_encode(
                    self.filename.format(**{'page_number': value}))

        except KeyError as e:
            from venc2.prompt import die
            die(messages.variable_error_in_filename.format(str(e)))

    # Overridden in child class (EntriesThread)
    def setup_context(self, entry):
        self.current_entry = entry

    def write_file(self, output, file_id):
        if self.in_thread:
            format_value = file_id

        else:
            format_value = page[0].id

        stream = codecs.open(self.export_path + '/' +
                             self.format_filename(format_value),
                             'w',
                             encoding="utf-8")
        stream.write(output.replace("\x1a", self.relative_origin))
        stream.close()

    def pre_iteration(self):
        global current_source
        self.processor.blacklist = self.forbidden
        current_source = self.header
        self.processor.process(current_source, safe_process=True)
        self.output = current_source.string
        current_source.restore()
        self.processor.blacklist = []
        self.columns_counter = 0
        self.columns = ['' for i in range(0, self.columns_number)]

    def post_iteration(self):
        global current_source
        self.columns_counter = 0
        for column in self.columns:
            self.output += self.column_opening.format(
                self.columns_counter) + column + self.column_closing

        self.processor.blacklist = self.forbidden

        current_source = self.footer
        self.processor.process(current_source, safe_process=True)
        self.output += current_source.string
        self.footer.restore()

        self.write_file(self.output.replace("\x1a", self.relative_origin),
                        self.page_number)

        self.page_number += 1
        self.current_page = self.page_number

    def do_iteration(self, entry):
        global current_source

        entry_wrapper = getattr(entry, self.content_type + "_wrapper")

        preprocessed_wrapper = getattr(entry, self.content_type +
                                       "_wrapper").processed_string
        self.processor.process(preprocessed_wrapper, safe_process=True)

        output = preprocessed_wrapper.string

        if entry_wrapper.process_get_entry_content:
            self.processor.process(entry.content, safe_process=True)
            output = output.replace("---VENC-GET-ENTRY-CONTENT---",
                                    entry.content.string)

        if entry_wrapper.process_get_entry_preview:
            self.processor.process(entry.preview, safe_process=True)
            output = output.replace("---VENC-GET-ENTRY-PREVIEW---",
                                    entry.preview.string)

        output = output.replace(
            "---VENC-PREVIEW-IF-IN-THREAD-ELSE-CONTENT---",
            entry.preview.string if self.in_thread else entry.content.string)

        self.columns[self.columns_counter] += output
        preprocessed_wrapper.restore()
        if entry_wrapper.process_get_entry_content:
            entry.content.restore()
        if entry_wrapper.process_get_entry_preview:
            entry.preview.restore()

        self.columns_counter += 1
        if self.columns_counter >= self.columns_number:
            self.columns_counter = 0

    def iterate_through_pages(self):
        for page in self.pages:
            self.pre_iteration()
            for entry in page:
                self.setup_context(entry)
                self.do_iteration(entry)

            self.post_iteration()

    # Must be called in child class
    def do(self):
        global current_source
        self.current_page = 0
        self.page_number = 0
        if self.pages_count == 0:
            current_source = self.header
            self.processor.process(current_source)
            output = current_source.string

            current_source = self.footer
            self.processor.process(current_source)
            output += current_source.string
            stream = codecs.open(self.export_path + '/' +
                                 self.format_filename(0),
                                 'w',
                                 encoding="utf-8")
            stream.write(output.replace("\x1a", self.relative_origin))
            stream.close()

        else:
            self.iterate_through_pages()
Exemple #9
0
class Thread:
    def __init__(self, prompt, datastore, theme, patterns_map):
        self.indentation_level = "│  "
        self.patterns_map = patterns_map
        self.datastore = datastore
        # Notify wich thread is processed
        if prompt != "":
            notify("├─ "+prompt)

        self.forbidden = patterns_map.non_contextual_entries_keys
        self.entries_per_page = int(datastore.blog_configuration["entries_per_pages"])
        self.disable_threads = datastore.disable_threads

        # Setup useful data
        self.theme = theme
        self.footer = deepcopy(self.theme.footer)
        self.header = deepcopy(self.theme.header)
        self.entry = deepcopy(self.theme.entry)
        self.context_header = "header.html"
        self.context_footer = "footer.html"
        self.content_type = "html"
        self.column_opening = '<div id="__VENC_COLUMN_{0}__" class="__VENC_COLUMN__">'
        self.column_closing = "</div>"
        self.columns_number = self.datastore.blog_configuration["columns"]
        # Setup pattern processor
        self.processor = Processor()
        for pattern_name in patterns_map.contextual["functions"].keys():
            self.processor.set_function(pattern_name, patterns_map.contextual["functions"][pattern_name])
                
        for pattern_name in patterns_map.contextual["names"].keys():
            self.processor.set_function(pattern_name, getattr(self, patterns_map.contextual["names"][pattern_name]))

    def return_page_around(self, string, params):
        return string.format(**params)

    # Must be called in child class
    def get_relative_location(self, argv):
        return self.export_path[5:]

    # Must be called in child class
    def organize_entries(self, entries):
        self.pages = list()
        for i in range(0, ceil(len(entries)/self.entries_per_page)):
            self.pages.append(
                entries[i*self.entries_per_page:(i+1)*self.entries_per_page]
            )

        self.pages_count = len(self.pages)

    # Must be called in child class
    def get_next_page(self, argv):
        if self.current_page < self.pages_count - 1:
            params = {
                "page_number" : str(self.current_page + 1),
                "entry_id" : '',
                "entry_title": '',
                "path" : ''
            }

            if self.in_thread:
                params["path"] = self.filename.format(**params)

            else:
                try:
                    params["path"] = self.current_entry.next_entry.url
                    params["entry_id"] = self.current_entry.next_entry.id
                    params["entry_title"] = self.current_entry.next_entry.title

                except AttributeError:
                    pass

            return argv[0].format(**params)

        else:
            return str()

    # Must be called in child class
    def get_previous_page(self, argv):
        if self.current_page > 0:
            params = {
                "page_number" : str(self.current_page - 1) if self.current_page - 1 != 0 else '',
                "entry_id" : '',
                "entry_title": '',
                "path" : ''
            }

            if self.in_thread:
                params["path"] = self.filename.format(**params)

            else:
                try:
                    params["entry_id"] = self.current_entry.previous_entry.id
                    params["entry_title"] = self.current_entry.previous_entry.title
                    params["path"] = self.current_entry.previous_entry.url
                except AttributeError:
                    pass

            return argv[0].format(**params)
        
        else:
            return str()

    # Must be called in child class
    def for_pages(self, argv):
        list_lenght = int(argv[0])
        string = argv[1]
        separator = argv[2]
            
        if self.pages_count <= 1:
            return str()

        output = str()
        page_number = 0
        for page in self.pages:
            if (not page_number < self.current_page - list_lenght) and (not page_number > self.current_page + list_lenght):
                try:
                    output += string.format(
                        **{
                            "entry_id":'',
                            "entry_title":'',
                            "page_number":str(page_number),
                            "path": self.filename.format(**{"page_number": (str() if page_number == 0 else page_number) })
                        }
                    ) + separator
                except KeyError as e:
                    print(e)
                    raise PatternInvalidArgument(name="string", value=string)

            page_number +=1
        
        return output[:-len(separator)]

    def JSONLD(self, argv):
        return ''

    def if_in_first_page(self, argv):
        if self.current_page == 0:
            return argv[0].strip()
        
        else:
            return argv[1].strip()

    def if_in_last_page(self, argv):
        if self.current_page == len(self.pages) -1:
            return argv[0].strip()
        
        else:
            return argv[1].strip()

    def if_in_entry_id(self, argv):
        return argv[2].strip()

    def if_in_categories(self, argv):
        return argv[1].strip()

    def if_in_archives(self, argv):
        return argv[1].strip()
        
    def if_in_thread(self, argv):
        if self.in_thread:
            return argv[0].strip()

        else:
            return argv[1].strip()

    def format_filename(self, value):
        try:
            if value == 0:
                return self.filename.format(**{
                    'page_number':''
                })
        
            else:
                return self.filename.format(**{
                    'page_number':value
                })

        except KeyError as e:
            die(messages.variable_error_in_filename.format(str(e)))

    # Overridden in child class (EntriesThread)
    def setup_context(self, entry):
        self.current_entry = entry

    def write_file(self, output, file_id):
        if self.in_thread:
            format_value = file_id

        else:
            format_value = page[0].id
                
        stream = codecs.open(
            self.export_path+'/'+self.format_filename(format_value),
            'w',
            encoding="utf-8"
        )
        stream.write(output)
        stream.close()

    def pre_iteration(self):
        self.processor.blacklist = self.forbidden
        self.processor.process(self.header, safe_process = True)
        self.output = self.header.string
        self.header.restore()
        self.processor.blacklist = []
        self.columns_counter = 0
        self.columns = [ '' for i in range(0, self.columns_number) ]
    
    def post_iteration(self):
        self.columns_counter = 0
        for column in self.columns:
            self.output += self.column_opening.format(self.columns_counter)+column+self.column_closing
            
        self.processor.blacklist = self.forbidden
        self.processor.process(self.footer, safe_process = True)
        self.output += self.footer.string
        self.footer.restore()
        
        self.write_file(self.output.replace(".:GetRelativeOrigin:.", self.relative_origin), self.page_number)

        self.page_number += 1
        self.current_page = self.page_number

    def do_iteration(self, entry):
        content_header = getattr(entry,self.content_type+"_wrapper").above
        self.processor.process(content_header, safe_process = True)
        self.columns[self.columns_counter] += content_header.string
        content_header.restore()
        
        if (entry.html_wrapper.required_content_pattern == ".:GetEntryPreview:.") or (entry.html_wrapper.required_content_pattern == ".:PreviewIfInThreadElseContent:." and self.in_thread):
            self.processor.process(entry.preview, safe_process = True)
            self.columns[self.columns_counter] += entry.preview.string
            entry.preview.restore()
                
        else: 
            self.processor.process(entry.content, safe_process = True)
            self.columns[self.columns_counter] += entry.content.string
            entry.content.restore()

        content_footer = getattr(entry,self.content_type+"_wrapper").below
        self.processor.process(content_footer, safe_process = True)
        self.columns[self.columns_counter] += content_footer.string
        content_footer.restore()

        self.columns_counter +=1
        if self.columns_counter >= self.columns_number:
            self.columns_counter = 0

    def iterate_through_pages(self):
        for page in self.pages:
            self.pre_iteration()
            for entry in page:
                self.setup_context(entry)
                self.do_iteration(entry)

            self.post_iteration()
    
    # Must be called in child class           
    def do(self):
        self.current_page = 0
        self.page_number = 0
        if self.pages_count == 0:
            self.processor.process(self.header)
            output = self.header.string

            self.processor.process(self.footer)
            output += self.footer.string
            stream = codecs.open(
                self.export_path +'/'+ self.format_filename(0),
                'w',
                encoding="utf-8"
            )
            stream.write(output.replace(".:GetRelativeOrigin:.", self.relative_origin))
            stream.close()
            
        else:
            self.iterate_through_pages()