# Path: matl_online/public/models.py
# class Release(Model):
#     """Model for storing metadata associated with MATL releases."""
# 
#     __tablename__ = 'releases'
# 
#     id = Column(db.Integer, primary_key=True)
#     tag = Column(db.String, unique=True, nullable=False)
#     date = Column(db.DateTime, unique=True, nullable=False)
# 
#     def __repr__(self):
#         """Create a custom string representation."""
#         return '<Release %r>' % self.tag
# 
#     @hybrid_property
#     def version(self):
#         """Convert release number to tuple for comparisons."""
#         return tuple(int(x) for x in self.tag.split('.'))
# 
#     @classmethod
#     def latest(cls):
#         """Get the latest release from Github."""
#         releases = cls.query.all()
#         if len(releases) == 0:
#             return None
# 
#         releases.sort(key=lambda x: x.version)
#         return releases[-1]
# 
# class DocumentationLink(Model):
#     """Model for storing hyperlinks to MATLAB's documentation."""
# 
#     __tablenamme__ = 'doclinks'
# 
#     id = Column(db.Integer, primary_key=True)
#     name = Column(db.String, unique=True, nullable=False)
#     link = Column(db.String, nullable=False)
# 
#     @classmethod
#     def refresh(cls):
#         """Fetch updated documentation from the Mathworks."""
#         # Flip the order of the links so that the first URL listed is the
#         # highest priority and will take precedence
#         for url in current_app.config['MATLAB_DOC_LINKS'][::-1]:
#             resp = requests.get(url)
#             soup = BeautifulSoup(resp.text, 'html.parser')
# 
#             terms = soup.findAll('td', {'class': 'term'})
#             links = [term.find('a') for term in terms]
# 
#             for link in links:
# 
#                 function = link.text.rstrip()
# 
#                 doc = cls.query.filter_by(name=function).first()
#                 doc_url = urljoin(url, link['href'])
# 
#                 # Create an entry if one doesn't already exist
#                 if doc is None:
#                     doc = cls(name=function)
# 
#                 doc.link = doc_url
#                 doc.save()
# 
#         # Make sure to remove i and j entries
#         toremove = cls.query.filter(or_(cls.name == 'i', cls.name == 'j')).all()
#         for item in toremove:
#             item.delete()
# 
#         return cls.query.all()
# 
# Path: matl_online/utils.py
# def unzip(fileobj, destination, flatten=True):
#     """Unzip an archive to a specific directory and flatten the shared prefix."""
#     archive = zipfile.ZipFile(fileobj)
# 
#     # Ensure that the destination exists
#     if not os.path.isdir(destination):
#         os.makedirs(destination)
# 
#     inputs = ()
# 
#     if flatten:
#         inputs = (get_members(archive),)
# 
#     archive.extractall(destination, *inputs)
# 
# def parse_iso8601(date):
#     """Convert a date in ISO 8601 format (used by github) to a datetime object."""
#     return datetime.strptime(date, ISO8601_FORMAT)
# 
# def base64_encode_file(filename):
#     """Load a file and return the base64-encoded version of the contents."""
#     with open(filename, 'rb') as fid:
#         return 'base64,' + base64.b64encode(fid.read()).decode()


import html
import json
import os
import re
import requests
import shutil
from flask import current_app
from io import BytesIO
from scipy.io import loadmat
from matl_online.public.models import Release, DocumentationLink
from matl_online.utils import unzip, parse_iso8601, base64_encode_file
    octave.eval(cmd)

    code = ["'%s'" % escape(item) for item in code.split('\n')]
    code = '{' + ','.join(code) + '}'

    if len(inputs):
        inputs = ["'%s'" % escape(item) for item in inputs.split('\n')]
        cmd = "matl_runner('%s', %s, %s);\n" % (flags, code, ','.join(inputs))
    else:
        inputs = None
        cmd = "matl_runner('%s', %s);\n" % (flags, code)

    # Actually run the MATL code
    octave.eval(cmd, line_handler=line_handler)

    # Change back to the original directory
    cmd = "cd('%s')" % escape(current_app.config['PROJECT_ROOT'])
    octave.eval(cmd)


def refresh_releases():
    """Fetch new release information from Github and update local database."""
    repo = current_app.config['MATL_REPO']
    resp = requests.get('https://api.github.com/repos/%s/releases' % repo)

    for item in resp.json():
        # Skip any pre-releases since they aren't ready for prime-time
        if item['prerelease']:
            continue


# Path: matl_online/public/models.py
# class Release(Model):
#     """Model for storing metadata associated with MATL releases."""
# 
#     __tablename__ = 'releases'
# 
#     id = Column(db.Integer, primary_key=True)
#     tag = Column(db.String, unique=True, nullable=False)
#     date = Column(db.DateTime, unique=True, nullable=False)
# 
#     def __repr__(self):
#         """Create a custom string representation."""
#         return '<Release %r>' % self.tag
# 
#     @hybrid_property
#     def version(self):
#         """Convert release number to tuple for comparisons."""
#         return tuple(int(x) for x in self.tag.split('.'))
# 
#     @classmethod
#     def latest(cls):
#         """Get the latest release from Github."""
#         releases = cls.query.all()
#         if len(releases) == 0:
#             return None
# 
#         releases.sort(key=lambda x: x.version)
#         return releases[-1]
# 
# class DocumentationLink(Model):
#     """Model for storing hyperlinks to MATLAB's documentation."""
# 
#     __tablenamme__ = 'doclinks'
# 
#     id = Column(db.Integer, primary_key=True)
#     name = Column(db.String, unique=True, nullable=False)
#     link = Column(db.String, nullable=False)
# 
#     @classmethod
#     def refresh(cls):
#         """Fetch updated documentation from the Mathworks."""
#         # Flip the order of the links so that the first URL listed is the
#         # highest priority and will take precedence
#         for url in current_app.config['MATLAB_DOC_LINKS'][::-1]:
#             resp = requests.get(url)
#             soup = BeautifulSoup(resp.text, 'html.parser')
# 
#             terms = soup.findAll('td', {'class': 'term'})
#             links = [term.find('a') for term in terms]
# 
#             for link in links:
# 
#                 function = link.text.rstrip()
# 
#                 doc = cls.query.filter_by(name=function).first()
#                 doc_url = urljoin(url, link['href'])
# 
#                 # Create an entry if one doesn't already exist
#                 if doc is None:
#                     doc = cls(name=function)
# 
#                 doc.link = doc_url
#                 doc.save()
# 
#         # Make sure to remove i and j entries
#         toremove = cls.query.filter(or_(cls.name == 'i', cls.name == 'j')).all()
#         for item in toremove:
#             item.delete()
# 
#         return cls.query.all()
# 
# Path: matl_online/utils.py
# def unzip(fileobj, destination, flatten=True):
#     """Unzip an archive to a specific directory and flatten the shared prefix."""
#     archive = zipfile.ZipFile(fileobj)
# 
#     # Ensure that the destination exists
#     if not os.path.isdir(destination):
#         os.makedirs(destination)
# 
#     inputs = ()
# 
#     if flatten:
#         inputs = (get_members(archive),)
# 
#     archive.extractall(destination, *inputs)
# 
# def parse_iso8601(date):
#     """Convert a date in ISO 8601 format (used by github) to a datetime object."""
#     return datetime.strptime(date, ISO8601_FORMAT)
# 
# def base64_encode_file(filename):
#     """Load a file and return the base64-encoded version of the contents."""
#     with open(filename, 'rb') as fid:
#         return 'base64,' + base64.b64encode(fid.read()).decode()


# Path: matl_online/matl.py
import html
import json
import os
import re
import requests
import shutil
from flask import current_app
from io import BytesIO
from scipy.io import loadmat
from matl_online.public.models import Release, DocumentationLink
from matl_online.utils import unzip, parse_iso8601, base64_encode_file

    octave.eval(cmd)

    code = ["'%s'" % escape(item) for item in code.split('\n')]
    code = '{' + ','.join(code) + '}'

    if len(inputs):
        inputs = ["'%s'" % escape(item) for item in inputs.split('\n')]
        cmd = "matl_runner('%s', %s, %s);\n" % (flags, code, ','.join(inputs))
    else:
        inputs = None
        cmd = "matl_runner('%s', %s);\n" % (flags, code)

    # Actually run the MATL code
    octave.eval(cmd, line_handler=line_handler)

    # Change back to the original directory
    cmd = "cd('%s')" % escape(current_app.config['PROJECT_ROOT'])
    octave.eval(cmd)


def refresh_releases():
    """Fetch new release information from Github and update local database."""
    repo = current_app.config['MATL_REPO']
    resp = requests.get('https://api.github.com/repos/%s/releases' % repo)

    for item in resp.json():
        # Skip any pre-releases since they aren't ready for prime-time
        if item['prerelease']:
            continue


        pubdate = parse_iso8601(item['published_at'])