text:
'''
    Note At various times system calls are evoked using the subprocess.pOpen
         To ensure that they work on 'Windows' systems the shell=True argument
         is required. This is a potential security issue so the use of this
         application should be restricted to trusted users.
    Note As a security measure this application can be disabled by setting
         the enabled setting in models/0.py to False

    Path through the installer
         - start Get some initial data for the AJAX app
         - setup_type Display the type of installer setup to run.
           - clone
             - appname (get the name of the app)
             - git (check that git is installed)
             - clone (clone Eden from git)
           - copy
             - copy (copy an existing version of Eden into a new folder)
             * update (Update the copy of Eden if required)
           - use
             - use an existing copy of Eden
           - update
         - python (Check that the required python libraries have been installed)
           * pip (Attempt to install all libraries that are required)
         - database (Find out what type of database will be used)
         - connect (Attempt to connect to that database)
         - base (Get basic information for the install)
         - template (Select the template to use)
         - module (Select the modules to use)
         * finished (Redirect to the newly installed Eden)
           - start the new Eden app (will this require a web2py restart?)
           - Can it gather the database create & then the prepop details?

    Note: the above is a guide to where work needs to be done
         - indicates completed
         * indicated unfinished or requires more testing
    Note: Each action will have a collection of methods associated with it
        - The main control method
        - The reply method used to return the json string
        - The dialog method used to get additional information (optional)

    @todo: Add a generic Ajax enabled progress bar and then add it
           to the "long processes", such as clone, copy, library install
    @todo: make check_python_libraries() a separate function in s3_update_check
    @todo: Tidy up the way information is reported, maybe two sections which are always displayed
    @todo: Ability to print to a file the install details
    @todo: Ability to print a debug file for remote assistance
'''

app = request.application
if not settings.enabled and (request.function != "disabled"):
    redirect("/%s/default/disabled" % app)

import json
import os

def error(): return dict()
def disabled():
    if settings.enabled:
        redirect("/%s/default/index" % app)
    return dict()

# Global settings for ajax callbacks
if request.ajax:
    action = request.function
    reply = Storage()
    reply.action = action
    reply.result = True
    reply.fatal = False
    reply.dialog = False
    reply.detail = ""
    reply.advanced = ""
elif request.function != "index":
    redirect("/%s/default/index" % app)

def index():
    try:
        # Python 2.7
        from collections import OrderedDict
    except:
        # Python 2.6
        from gluon.contrib.simplejson.ordered_dict import OrderedDict
    #session.eden_release = T("Eden release 1.0")
    session.eden_release = T("Eden trunk") # replace once we have a release
    session.fatal = None
    response.title=T("Sahana Eden Web Setup")
    actions = OrderedDict()
    actions["setup_type"] = T("Type of setup")
    actions["appname"] = T("Getting the application name")
    actions["git"] = T("Looking for git")
    actions["clone"] = T("Cloning Sahana Eden")
    actions["python"] = T("Looking for Python libraries")
    actions["pip"] = T("Looking for pip")
    actions["install"] = T("Using pip to install missing libraries")
    actions["database"] = T("Selecting the database to use")
    actions["connect"] = T("Connecting to the database")
    actions["base"] = T("Basic system settings")
    actions["template"] = T("Select the template to use")
    actions["modules"] = T("Select modules to enable")
    table = TABLE()
    for (key,value) in actions.items():
        table.append(TR(
                        TD(value, _id="%s" % key),
                        TD(IMG(_id="%s_wait" % key,
                               _src="/%s/static/images/Waiting.png" % app),
                           IMG(_id="%s_process" % key,
                               _src="/%s/static/images/ajax-loader.gif" % app,
                               _class="hidden"),
                           IMG(_id="%s_pass" % key,
                               _src="/%s/static/images/Pass.png" % app,
                               _class="hidden"),
                           IMG(_id="%s_fail" % key,
                               _src="/%s/static/images/Fail.png" % app,
                               _class="hidden")
                          )
                       )
                    )
    response.basic=table
    script = """
app = "%s";
success = function(_data){
    data = $.parseJSON(_data) // Global scope so that dialog events can access it
    if (data.html) {$("#dialogs").html(data.html);};
    if (data.script){
        if (!window.location.origin)
            {window.location.origin = window.location.protocol+"//"+window.location.host;}
        $.getScript(window.location.origin + '/edenstart/' + data.script)
           .done(function(){dashboard_update();})
           .fail(function( jqxhr, settings, exception ) {throw exception;});
    } else {
        dashboard_update();
    }
}

dashboard_update = function(){
    if (data.subaction){
        $("#"+data.subaction+"_wait").hide();
        $("#"+data.subaction+"_process").hide();
    } else {
        $("#"+data.action+"_wait").hide();
        $("#"+data.action+"_process").hide();
    }
    if (data.result) {
        if (data.subaction){
            $("#"+data.subaction+"_pass").show();
            $("#"+data.subaction+"_fail").hide();
        } else {
            $("#"+data.action+"_pass").show();
            $("#"+data.action+"_fail").hide();
        }
    } else {
        if (data.subaction){
            $("#"+data.subaction+"_pass").hide();
            $("#"+data.subaction+"_fail").show();
        } else {
            $("#"+data.action+"_pass").hide();
            $("#"+data.action+"_fail").show();
        }
    }
    $("#detail").append("
"+data.action+": "+data.detail+"
");
    if (data.advanced != "") {
        $("#advanced").append("
"+data.action+": "+data.advanced+"
");
    }
    if (data.insert_basic){
        insert_basic(data.insert_basic_id, data.insert_basic_html);
    }
    if (data.fatal){
        alert(data.fatal);
        return;
    }
    if (data.next != 'finished') {
        if (data.nextsubaction){
            $("#"+data.nextsubaction+"_wait").hide();
            $("#"+data.nextsubaction+"_process").show();
        }
        $("#"+data.next+"_wait").hide();
        $("#"+data.next+"_process").show();
        if (data.dialog){
            $(data.dialog).on("dialogclose", function(event, ui){user_abort();});
            $(data.dialog).dialog("open");
        } else {
            $.get('/'+app+'/default/'+data.next).done(function(data){success(data)});
        }
    }
}

function user_abort(){
    if (unexpected_close) {
        $("#"+data.next+"_process").hide();
        $("#detail").append("
User Aborted.
");
    }
}

function insert_basic(id, html){
    $("td#"+id).append(html);
}

$.get('/'+app+'/default/start').done(function(data){success(data)});

function updateTips( t ) {
    $(".validateTips").text(t).addClass( "ui-state-highlight" );
    setTimeout(function() {
        $(".validateTips").removeClass( "ui-state-highlight", 1500 );
    }, 500 );
}
checkLength = function( o, n, min, max ) {
    if ( o.val().length > max || o.val().length < min ) {
        o.addClass( "ui-state-error" );
        updateTips( "Length of " + n + " must be between " + min + " and " + max + "." );
        return false;
    } else {
        return true;
    }
}
checkRegexp = function (o, regexp, n) {
    if (!(regexp.test(o.val())) ) {
        o.addClass("ui-state-error");
        updateTips(n);
        return false;
    } else {
        return true;
    }
}
checkRestrict = function(o, n, exclude){
    for (i=0; i<exclude.length; i++){
        if (o.val() == exclude[i]){
            o.addClass("ui-state-error");
            updateTips(n);
            return false;
        }
    }
    return true;
}
""" % (app)
    return dict(script=script)

'''
    check_000_config
    ==============
    Check that the config file exists, and read the contents if it does
'''
def check_000_config():
    appname = session.appname
    # Read in the 000_config file
    base_cfg_file = "applications/%s/models/000_config.py" % appname
    try:
        input = open(base_cfg_file)
        with open(base_cfg_file, "r") as file:
            data = file.readlines()
    except:
        return False
    return data

'''
    load_000_config
    ==============
    Load the config file, if it doesn't exist create it and then read the contents
'''
def load_000_config():
    appname = session.appname
    data = check_000_config()
    if data == False:
        # No file so need to copy from templates
        # NOTE this code was copied from s3_upade_check (see check_python_libraries @todo)
        template_cfg_file = "applications/%s/private/templates/000_config.py" % appname
        base_cfg_file = "applications/%s/models/000_config.py" % appname
        input = open(template_cfg_file)
        output = open(base_cfg_file, "w")
        for line in input:
            if "akeytochange" in line:
                # Generate a random hmac_key to secure the passwords in case
                # the database is compromised
                import uuid
                hmac_key = uuid.uuid4()
                line = 'deployment_settings.auth.hmac_key = "%s"' % hmac_key
            output.write(line)
        output.close()
        input.close()
        input = open(base_cfg_file)
        with open(base_cfg_file, "r") as file:
            data = file.readlines()
    return data

'''
    get_000_config
    ==============
    Get an attribute from the config file
'''
def get_000_config(attr, default=None):
    data = load_000_config()
    if attr[-1] != " ":
        attr = attr + " "
    value = default
    for line in data:
        if attr in line and line[0] != "#":
            endvalue =line[line.rfind("= ")+2:-1]
            try:
                value = endvalue.split('"')[1]
            except: # value is not a string is it a number
                try:
                    value = int(endvalue)
                except: # could the value be a boolean
                    if endvalue == "True":
                        value = True
                    else:
                        value = False
    return value

'''
    set_000_config
    ==============
    Set an attribute in the config file with the given value
'''
def set_000_config(attr, value, comment=False):
    if attr[-1] != " ":
        attr = attr + " "
    # Read in the 000_config file
    data = check_000_config()
    if data == False:
        return False
    added = False
    attr_found = False
    cnt = 0
    for line in data:
        if attr in line:
            attr_found = True
            if value and value in line:
                while data[cnt][0] == "#":
                    data[cnt] = line[1:]
                added = True
            else:
                if line[0] != "#":
                    data[cnt] = "#%s" % line
        cnt += 1
    if not comment and not added:
        if attr_found:
            cnt = 0
            for line in data:
                if attr in line:
                    data[cnt] = "settings.%s = %s\n%s" % (attr, value, line)
                    break # so it is only added once
                cnt += 1
        else:
            # add the attr at the end of the file
            data.append("settings.%s = %s\n" % (attr, value))

    appname = session.appname
    base_cfg_file = "applications/%s/models/000_config.py" % appname
    with open(base_cfg_file, 'w') as file:
        file.writelines( data )

def file_check(*path):
    """
        path this is a list of directories ending with the file
        Usage : files_check("sub_directory","another_sub_directory", "File.txt")
        returns a boolean value (True/False)
    """
    path = os.path.join("applications",*path)
    return os.path.isfile(path)

def directory_check(*directories):
    """
        directories : this is a list of all sub-directories and also includes the the directory to check.
        Usage : directory_check("directory","sub_directory","another_sub_directory")
        returns a boolean value (True/False)
    """
    path = os.path.join("applications",
                        *directories)
    return os.path.isdir(path)

def read_config_file(appname, template):
    """
        Utility to read the selected config file
        appname: the name of teh selected application
        template: the name of the selected template
    """
    base_cfg_file = os.path.join("applications",
                                 appname,
                                 "private",
                                 "templates",
                                 template,
                                 "config.py"
                                 )
    with open(base_cfg_file, "r") as file:
        data = file.readlines()
    return data

'''
    start
    =====
    This gets some of the data that the Ajax app will use
    It then displays the setup type dialog
'''
def start():
    def get_known_apps():
        known_apps = []
        ls = os.listdir("applications")
        for obj in ls:
            if directory_check(obj, ".git"):
                known_apps.append(obj)
        return known_apps

    def get_eden_apps():
        eden_apps = []
        testLine = "Sahana Eden is an Emergency Development Environment"
        ls = os.listdir("applications")
        for app in session.known_apps:
            if directory_check(app, "modules","s3") and \
               directory_check(app, "private", "templates") and \
               file_check(app, "ABOUT"):
                file = open(os.path.join("applications", app, "ABOUT"))
                if file.read(len(testLine)) == testLine:
                    eden_apps.append(app)
        return eden_apps

    session.known_apps = get_known_apps() # used by appname
    session.eden_apps = get_eden_apps()   # used by use_existing
    reply.detail = "Existing web2py apps are: %s" % session.known_apps
    reply.next = "setup_type"
    reply.dialog = "#setup-type-form"
    (reply.html, reply.script) = setup_type_dialog(app)
    return json.dumps(reply)

'''
    setup_type
    ==========
    This will ask the user what type of setup they wish to perform
'''
def setup_type():
    if not request.ajax:
        redirect("/%s/default/index" % app)

    setup_type = request.get_vars.setup_type
    session.setup_type = setup_type
    reply.detail = reply.detail + T("Setup type %s selected" % setup_type,
                                    lazy = False)
    if session.setup_type == "clone":
        reply.next = "appname"
        reply.exclude_list = session.known_apps
        reply.dialog = "#app-name-form"
        (reply.html, reply.script) = appname_dialog(app)
    elif session.setup_type == "copy":
        reply.next = "copy"
        reply.exclude_list = session.known_apps
        reply.dialog = "#copy-eden-form"
        (reply.html, reply.script) = copy_dialog(app)
    elif session.setup_type == "use":
        reply.next = "use"
        reply.dialog = "#use-eden-form"
        (reply.html, reply.script) = use_dialog(app, reply)
    else:
        reply.next = "finish"
    return json.dumps(reply)

def setup_type_dialog(app):
    setup = DIV(_id="setup-type-form",
                  _title=T("Select the type of setup you want to perform")
                 )
    setup.append(TABLE(
                       TR(TD(INPUT(_id = "setup_clone",
                             _name = "setup_type_in",
                             _type = "radio",
                             _value = "clone"
                            )),
                            TD(LABEL(T("Clone from git hub")))
                       ),
                       TR(TD(INPUT(_id = "setup_copy",
                             _name = "setup_type_in",
                             _type = "radio",
                             _value = "copy"
                            )),
                          TD(LABEL(T("Copy an existing Eden install")))
                       ),
                       TR(TD(INPUT(_id = "setup_use",
                             _name = "setup_type_in",
                             _type = "radio",
                             _value = "use",
                             _checked = True
                            )),
                          TD(LABEL(T("Use an existing unused Eden install")))
                       ),
                       TR(TD(INPUT(_id = "setup_update",
                             _name = "setup_type_in",
                             _type = "radio",
                             _value = "update",
                             _disabled="disabled"
                            )),
                          TD(LABEL(T("Update an existing Eden install (requires authentication)")))
                       ),
                       TR(TD(),
                          TD(I(T("Update is not yet enabled")))
                       )
                      ),
                  )
    script = "static/js/setuptype.js"
    return (setup.xml(), script)

'''
    appname
    =======
    Used to get from the user the name of the app they will create
'''
def appname():
    def appname_json(reply):
        appname = request.get_vars.appname
        reply.detail = T("Appname will be %s" % appname, lazy = False)
        session.appname =  appname
        path = os.path.join("applications", appname)
        if os.path.isdir(path):
            if os.path.isdir(os.path.join(path, ".git")):
                reply.detail = reply.detail +\
                               "
" +\
                               T("Directory %s already exists, so %s will not be cloned" % (appname, session.eden_release),
                                                lazy = False)
                reply.dialog = "#app-exists-alert"
                reply.next = "python"
                return json.dumps(reply)
        return json.dumps(reply)

    if not request.ajax:
        redirect("/%s/default/index" % app)

    setup_type = session.setup_type
    if setup_type == "clone":
        reply.next = "git"
    else:
        reply.next = "clone"
    return appname_json(reply)

def appname_dialog(app):
    appName = DIV(_id="app-name-form",
                  _title=T("Enter an application name")
                 )
    appName.append(P(T("Enter the name you will call your application"),
                     _class="validateTips"))
    appName.append(FORM(LABEL(T("Application name")),
                        INPUT(_id = "appname_in",
                              _name = "appname_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = "test"
                             )
                        )
                   )
    script = "static/js/appname.js"
    return (appName.xml(), script)

'''
    git
    ===
    Used to check that git can be accessed from within Python.
    This is needed if the code is to be cloned from github
'''
def git():
    def git_json(reply):
        from subprocess import Popen, PIPE
        try:
            cmd = ["git --version"]
            p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
            (myout, myerr) = p.communicate()
            reply.detail = T("Looking for git, found: %s" % myout, lazy = False)
            if myerr:
                reply.result = False
                reply.fatal = T("Unable to continue, please install git",
                                lazy=False)
                reply.detail = "%s
" %(reply.fatal)
                reply.advanced = myerr
        except Exception, inst:
            reply.result = False
            reply.fatal = T("Unable to continue, please install git",
                            lazy=False)
            reply.detail = "%s
" %(reply.fatal)
            reply.advanced = "command:%s
exception:%s
" % (" ".join(cmd), inst)
        reply.next = "clone"
        return json.dumps(reply)

    if not request.ajax:
        redirect("/%s/default/index" % app)

    reply.next = "clone"
    return git_json(reply)

'''
    Clone
    =====
    This will take a copy of Eden from gitHub and clone it to the appname directrory
'''
def clone():
    def clone_json(reply):
        from subprocess import Popen, PIPE
        try:
            appname = session.appname
            eden = session.eden_release
            # @todo: The clone command should be controlled so that different
            #        sources can be selected.
            #        This will allow support for releases and local versions.
            cmd = ["git clone https://github.com/flavour/eden.git applications/%s" % appname]
            p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
            (myout, myerr) = p.communicate()
            retcode = p.returncode
            if retcode != 0:
                reply.result = False
                reply.fatal = T("Unable to clone %s" % eden,
                                lazy=False)
                reply.detail = T("Cloning %s into application %s: Failed" % (eden, appname),
                                 lazy = False)
                if myerr == "":
                    reply.advanced = "command: %s
error: %s
" % (" ".join(cmd), myout)
                else:
                    reply.advanced = "command: %s
error: %s
" % (" ".join(cmd), myerr)
            else:
                reply.detail = T("Cloning %s into application %s:
%s" % (eden, appname, myout),
                                 lazy = False)
                reply.advanced = "command: %s
" % (" ".join(cmd))
        except Exception, inst:
            reply.result = False
            reply.fatal = T("Unable to clone %s" % eden,
                            lazy=False)
            reply.detail = reply.fatal + "
"
            reply.advanced = "command: %s
exception:%s
" % (" ".join(cmd), inst)
            reply.next = "finished"
        return json.dumps(reply)

    if not request.ajax:
        redirect("/%s/default/index" % app)

    reply.next = "python"
    return clone_json(reply)

'''
    Copy
    ====
    This will take a copy of an existing install of Eden
'''
def copy():
    def copy_json(reply):
        old_appname = request.get_vars.copy_appname
        new_appname = request.get_vars.appname
        from shutil import copytree, ignore_patterns
        source = os.path.join("applications", old_appname)
        destination = os.path.join("applications", new_appname)
        try:
            copytree(source, destination, ignore=ignore_patterns("errors*", "databases*", "sessions", "uploads*"))
            reply.detail = T("Eden directory has been successfully copied into %s" % new_appname,
                              lazy=False)
        except Exception, inst:
            reply.result = False
            reply.fatal = T("Unable to copy %s" % new_appname,
                            lazy=False)
            reply.detail = reply.fatal + "
"
            reply.advanced = "command: copytree(%s, %s,ignore=ignore_patterns(\"errors*\", \"databases*\", \"sessions\", \"uploads*\"))
exception:%s
" % (source, destination, inst)
            reply.next = "finished"
        # If an active 000_config file has been copied then set FINISHED_EDITING_CONFIG_FILE to False
        session.appname = new_appname
        if check_000_config():
            set_000_config("FINISHED_EDITING_CONFIG_FILE", False)

        return json.dumps(reply)

    if not request.ajax:
        redirect("/%s/default/index" % app)

    session.old_appname = request.get_vars.copy_appname
    session.new_appname = request.get_vars.appname
    reply.next = "python"
    return copy_json(reply)

def copy_dialog(app):
    copy = DIV(_id="copy-eden-form",
                  _title=T("Copy Eden")
                 )
    copy_table = TABLE()
    copy_table.append(TD(T("Select the eden application you want to copy")))
    copy.append(copy_table)
    copy_table = TABLE()
    for eden in session.eden_apps:
        copy_table.append(TR(TD(INPUT(_id = "app_%s" % eden,
                                      _name = "app_name_in",
                                      _type = "radio",
                                      _value = eden,
                                      _checked = True
                                      )),
                            TD(LABEL(eden))
                       ))
    copy.append(copy_table)
    copy_table = TABLE()
    copy_table.append(TD(T("Enter the name you will call your application"),
                      _class="validateTips",
                      _colspan = 2),
                     )
    copy_table.append(TR(TD(LABEL(T("Name"))),
                         TD(INPUT(_id = "appname_in",
                                  _name = "appname_in",
                                  _class="text ui-widget-content ui-corner-all",
                                  value = "test"
                                  )
                            )
                        )
                   )
    copy.append(copy_table)
    script = "static/js/copyapp.js"
    return (copy.xml(), script)

'''
    Use
    ===
    Select an unused install to set up
'''
def use():
    def use_json(reply):
        session.appname = request.get_vars.appname
        reply.detail = T("Using application %s" % session.appname, lazy=False)
        return json.dumps(reply)

    if not request.ajax:
        redirect("/%s/default/index" % app)

    reply.next = "python"
    return use_json(reply)

def use_dialog(app, reply):
    use = DIV(_id="use-eden-form",
              _title=T("Copy Eden")
             )
    use_table = TABLE()
    use_table.append(TD(T("Select the eden application you want to use")))
    use.append(use_table)
    use_table = TABLE()
    found = False
    appname = session.appname
    for eden in session.eden_apps:
        session.appname = eden # set session.appname to access the config file
        if check_000_config():
            if get_000_config("FINISHED_EDITING_CONFIG_FILE", True):
                continue
        found = True
        use_table.append(TR(TD(INPUT(_id = "app_%s" % eden,
                                      _name = "app_name_in",
                                      _type = "radio",
                                      _value = eden,
                                      _checked = True
                                      )),
                            TD(LABEL(eden))
                       ))
    if not found:
        reply.next = "finished"
        reply.detail += "
" + T("No available application could be found.", lazy=False)

    session.appname = appname # reset session.appname
    use.append(use_table)
    script = "static/js/useapp.js"
    return (use.xml(), script)

'''
    Python
    ======
    Check that the required python libraries are installed

    @todo: use T() for all strings...
'''
def python():
    def strip_lib(msg):
        needle = "unresolved dependency: "
        start = msg.find(needle) + len(needle)
        finish = msg.find(" ", start)
        lib = msg[start:finish]
        return lib

    def python_json(reply):
        result = check_libraries()
        libs_missing = False
        error_lib = []
        warning_lib = []
        if result["error_messages"]:
            for error in result["error_messages"]:
                error_lib.append(strip_lib(error))
                reply.detail = reply.detail + "Error: %s
" % error
                reply.advanced = reply.advanced + "Error: %s
" % error
                libs_missing = True
        else:
            reply.detail = T("No essential libraries missing", lazy=False)
        if result["warning_messages"]:
            for warning in result["warning_messages"]:
                warning_lib.append(strip_lib(warning))
                reply.advanced = reply.advanced + "Warning: %s
" % warning
                libs_missing = True
        if libs_missing:
            reply.next = "pip"
            session.error_lib = error_lib
            session.warning_lib = warning_lib
            table = TABLE()
            app = request.application
            for lib in error_lib:
                table.append(TR(
                                TD(IMG(_src="/%s/static/images/red_star.png" % app,
                                       _width=24, _height=24),
                                   T("Install python library %s" % lib), _id="%s" % lib),
                                TD(IMG(_id="%s_wait" % lib,
                                       _src="/%s/static/images/Waiting.png" % app,
                                       _width=24, _height=24),
                                   IMG(_id="%s_process" % lib,
                                       _src="/%s/static/images/ajax-loader.gif" % app,
                                       _width=24, _height=24,
                                       _class="hidden",
                                       _style="display: none"),
                                   IMG(_id="%s_pass" % lib,
                                       _src="/%s/static/images/Pass.png" % app,
                                       _width=24, _height=24,
                                       _class="hidden",
                                       _style="display: none"),
                                   IMG(_id="%s_fail" % lib,
                                       _src="/%s/static/images/Fail.png" % app,
                                       _width=24, _height=24,
                                       _class="hidden",
                                       _style="display: none")
                                  )
                               )
                            )
            for lib in warning_lib:
                table.append(TR(
                                TD(IMG(_src="/%s/static/images/yellow_star.png" % app,
                                       _width=16, _height=16),
                                   T("Install python library %s" % lib), _id="%s" % lib),
                                TD(IMG(_id="%s_wait" % lib,
                                       _src="/%s/static/images/Waiting.png" % app,
                                       _width=24, _height=24),
                                   IMG(_id="%s_process" % lib,
                                       _src="/%s/static/images/ajax-loader.gif" % app,
                                       _width=24, _height=24,
                                       _class="hidden",
                                       _style="display: none"),
                                   IMG(_id="%s_pass" % lib,
                                       _src="/%s/static/images/Pass.png" % app,
                                       _width=24, _height=24,
                                       _class="hidden",
                                       _style="display: none"),
                                   IMG(_id="%s_fail" % lib,
                                       _src="/%s/static/images/Fail.png" % app,
                                       _width=24, _height=24,
                                       _class="hidden",
                                       _style="display: none")
                                  )
                               )
                            )
            reply.insert_basic = True
            reply.insert_basic_html = table.xml()
            reply.insert_basic_id = "install"
            reply.dialog = "#missing-libs-alert"
            (reply.html, reply.script) = pip_dialog(app)
            return json.dumps(reply)
        else:
            return pre_db_json(reply)

    return python_json(reply)

def check_libraries():
    '''
        Check for python libraries
    '''
    from gluon.shell import exec_environment
    appname = session.appname
    module = "applications/%s/modules/s3_update_check.py" % appname
    s3check = exec_environment(module)
    warnings = []
    errors = []

    result = s3check.s3_check_python_libraries()
    errors = result [0]
    warnings = result [1]
    return {"error_messages":errors,"warning_messages":warnings}

'''
    Pip
    ======
    Check that pip is installed so that it can install the required python libraries
'''
def pip():
    def pip_json(reply):
        from subprocess import Popen, PIPE
        import platform
        windows = platform.system() == "Windows"
        try:
            cmd = ["pip", "--version"]
            p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=windows)
            (myout, myerr) = p.communicate()
            if p.returncode == 0:
                reply.detail = T("Looking for pip, found: %s" % myout.replace('\n', '
'),
                                 lazy = False)
                reply.advanced = myerr
            else:
                reply.fatal = T("Unable to continue, please install pip",
                                lazy=False)
                reply.detail = "%s
" %(reply.fatal)
                reply.advanced = "command:%s
exception:%s
" % (" ".join(cmd),
                                                                                myout.replace('\n', '
'))
        except Exception, inst:
            reply.result = False
            reply.fatal = T("Unable to continue, please install pip",
                            lazy=False)
            reply.detail = "%s
" %(reply.fatal)
            reply.advanced = "command:%s
exception:%s
" % (" ".join(cmd), inst)
            return json.dumps(reply)
        # Now see if the version of pip supports the --target install option
        cmd = ["pip", "install", "--target"]
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=windows)
        (myout, myerr) = p.communicate()
        if "no such option" in myerr:
            reply.result = False
            reply.fatal = T("The version of pip needs to be upgraded. Use 'pip install -U pip' as admin.",
                            lazy=False)
            reply.detail = reply.detail +\
                           "
" +\
                           "%s
" %(reply.fatal)
            reply.advanced = reply.advanced +\
                             "command:%s
error:%s
" % (" ".join(cmd), myerr)
        else:
            reply.detail = reply.detail +\
                           "
" +\
                           T("Looking for pip install --target option, found:", lazy = False)
            reply.next = "install"
            if session.error_lib:
                reply.nextsubaction = session.error_lib[0]
            elif session.warning_lib:
                reply.nextsubaction = session.warning_lib[0]
        return json.dumps(reply)
    # End of pip_json

    if request.get_vars.button == "install":
        return pip_json(reply)
    elif request.get_vars.button == "skip":
        reply.detail = T("Installation of missing libraries skipped", lazy = False),
        return pre_db_json(reply)

def pip_dialog(app):
    libsdiv = DIV(_id="missing-libs-alert",
                     _title=T("Missing Libraries")
                   )
    libsdiv.append(P(T("Some libraries that Eden uses are missing. Would you like the system to try and install them for you? To do this it is necessary to have pip installed.")))
    script = "static/js/pip.js"
    return (libsdiv.xml(), script)

def db_type_dialog(app):
    dbType = DIV(_id="db-type-form",
                  _title=T("Database type")
                 )
    dbType.append(P(T("Select the type of database that will be used.")))
    dbType.append(TABLE(
                        TR( TD(INPUT(_id = "dbtype_sqlite",
                             _name = "dbtype_in",
                             _type = "radio",
                             _value = "sqlite"
                            )),
                            TD(LABEL(T("Sqlite")))
                        ),
                       TR( TD(INPUT(_id = "dbtype_mysql",
                             _name = "dbtype_in",
                             _type = "radio",
                             _value = "mysql"
                            )),
                          TD(LABEL(T("MySql")))
                       ),
                       TR(TD(INPUT(_id = "dbtype_postgres",
                             _name = "dbtype_in",
                             _type = "radio",
                             _value = "postgres"
                            )),
                          TD(LABEL(T("PostgeSQL")))
                       )
                      ),
                  )
    script = "static/js/db_type.js"
    return (dbType.xml(), script)

def install():
    def install_json(reply):
        '''
            This function will attempt to install the missing libraries
            Because of the time it takes to install each library it will
            do one at a time and then send the result back as an json string
        '''
        def pip_install(reply, lib, fatal):
            '''
                Function that will use pip to attempt to install the missing python library
            '''
            from subprocess import Popen, PIPE
            import platform
            windows = (platform.system() == "Windows")

            target = os.path.join(request.env.web2py_path, "site-packages")
            cmd = ["pip", "install", "--target", target, lib]
            p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=windows)
            (myout, myerr) = p.communicate()
            if p.returncode == 0:
                reply.detail = reply.detail + "
"+T("Installed %s library" % lib,
                                                       lazy = False)
                reply.advanced = reply.advanced +\
                                "command:%s
" % (" ".join(cmd))
            else:
                reply.detail = reply.detail + "
"+T("Failed to install %s library." % (lib),
                                                       lazy = False)
                reply.advanced = reply.advanced +\
                                "command:%s
error:%s
%s
" % (" ".join(cmd),
                                                                              myout.replace('\n', '
'),
                                                                              myerr.replace('\n', '
'))
                if fatal:
                    session.fatal = T("Failed to install all of the required libraries",
                                    lazy=False)
                reply.result = False
            return reply
        # Install a required lib, if one exists
        lib = None
        if session.error_lib:
            lib = session.error_lib.pop(0)
            reply = pip_install(reply, lib, True)
        # Install an optional lib, if one exists
        elif session.warning_lib:
            lib = session.warning_lib.pop(0)
            reply = pip_install(reply, lib, False)
        if lib:
            reply.subaction = lib
            if session.error_lib:
                reply.nextsubaction = session.error_lib[0]
            elif session.warning_lib:
                reply.nextsubaction = session.warning_lib[0]
            reply.next = "install"
        else:
            if session.fatal:
                reply.fatal = session.fatal
                reply.result = False
            return pre_db_json(reply)
        return json.dumps(reply)
    # End of function install_json

    return install_json(reply)

def pre_db_json(reply):
    reply.dialog = "#db-type-form"
    (reply.html, reply.script) = db_type_dialog(app)
    reply.next = "database"
    db_type = get_000_config("db_type", "sqlite")
    reply.db_type = db_type
    return json.dumps(reply)

def database():
    def db_json(reply):
        db_type = request.get_vars.db_type
        session.db_type = db_type
        set_000_config("database.db_type",
                       '"%s"'%db_type,
                       comment=(db_type=="sqlite")
                      )
        reply.detail = reply.detail + T("type %s selected" % db_type,
                                        lazy = False)
        return pre_connect_json(reply)

    def pre_connect_json(reply):
        db_type = session.db_type
        if db_type == "sqlite":
            set_000_config("database.host","",True)
            set_000_config("database.port","",True)
            set_000_config("database.database","",True)
            set_000_config("database.username","",True)
            set_000_config("database.password","",True)
            reply.next = "connect"
        elif db_type == "mysql":
            reply.dialog = "#db-connect-form"
            (reply.html, reply.script) = connect_dialog(app)
            reply.next = "connect"
            reply.db_host = get_000_config("host", "localhost")
            if get_000_config("database.db_type", "") == "mysql":
                reply.db_port = get_000_config("port", "3306")
            else:
                reply.db_port = "3306"
            reply.db_schema = get_000_config("schema", "sahana")
            reply.db_user = get_000_config("user", "sahana")
            reply.db_password = get_000_config("password", "")
        elif db_type == "postgres":
            reply.dialog = "#db-connect-form"
            (reply.html, reply.script) = connect_dialog(app)
            reply.next = "connect"
            reply.db_host = get_000_config("host", "localhost")
            if get_000_config("database.db_type", "") == "postgres":
                reply.db_port = get_000_config("port", "5432")
            else:
                reply.db_port = "5432"
            reply.db_schema = get_000_config("schema", "sahana")
            reply.db_user = get_000_config("user", "sahana")
            reply.db_password = get_000_config("password", "")
        return json.dumps(reply)

    return db_json(reply)

def connect_dialog(app):
    connect = DIV(_id="db-connect-form",
                  _title=T("Enter the database details")
                 )
    connect.append(P(T("Provide the details necessary to connect to the database"),
                     _class="validateTips"))
    connect.append(FORM(LABEL(T("Database host")),
                        INPUT(_id = "db_host_in",
                              _name = "db_host_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = ""
                             ),
                        LABEL(T("Database port")),
                        INPUT(_id = "db_port_in",
                              _name = "db_port_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = ""
                             ),
                        LABEL(T("Database schema name")),
                        INPUT(_id = "db_schema_in",
                              _name = "db_schema_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = ""
                             ),
                        LABEL(T("Database username")),
                        INPUT(_id = "db_user_in",
                              _name = "db_user_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = ""
                             ),
                        LABEL(T("Database password")),
                        INPUT(_id = "db_password_in",
                              _name = "db_password_in",
                              _type = "password",
                              _class="text ui-widget-content ui-corner-all",
                              value = ""
                             ),
                        )
                   )
    script = "static/js/db_connect.js"
    return (connect.xml(), script)

def connect():
    def connect_json(reply):
        db_type = session.db_type
        db_host = request.get_vars.db_host
        db_port = request.get_vars.db_port
        db_schema = request.get_vars.db_schema
        db_user = request.get_vars.db_user
        db_password = request.get_vars.db_password
        set_000_config("database.host",
                       '"%s"'%db_host,
                       comment=(db_type=="sqlite")
                      )
        set_000_config("database.port",
                       db_port,
                       comment=(db_type=="sqlite")
                      )
        set_000_config("database.database",
                       '"%s"'%db_schema,
                       comment=(db_type=="sqlite")
                      )
        set_000_config("database.username",
                       '"%s"'%db_user,
                       comment=(db_type=="sqlite")
                      )
        set_000_config("database.password",
                       '"%s"'%db_password,
                       comment=(db_type=="sqlite")
                      )
        # Now construct the database string
        if (db_type == "sqlite"):
            db_string = "sqlite://storage.db"
        elif (db_type == "mysql"):
            db_string = "mysql://%s:%s@%s:%s/%s" % \
                        (db_user, db_password, db_host, db_port, db_schema)
        elif (db_type == "postgres"):
            db_string = "postgres://%s:%s@%s:%s/%s" % \
                        (db_user, db_password, db_host, db_port, db_schema)
        reply = db_connect(reply, db_string)
        return json.dumps(reply)
    return connect_json(reply)

def db_connect(reply, db_string):
    # attempt to connect using the string
    try:
        db = DAL(db_string)
        session.db_string = db_string
        reply.detail = reply.detail + "
"+T("Connection to database successful.",
                                               lazy = False)
        reply.advanced = reply.advanced +\
                        "Connection using database string %s succeeded
" % db_string
        reply.dialog = "#sys-base-form"
        reply.next = "base"
        (reply.html, reply.script) = base_dialog(app)
    except:
        reply.result = False
        reply.detail = reply.detail + "
"+T("Connection to database failed",
                                               lazy = False)
        reply.advanced = reply.advanced +\
                        "Connection using database string %s failed
" % db_string
        reply.dialog = "#db-type-form"
        reply.next = "database"
    return reply

def base():
    def pre_template_json(reply):
        template_path = "applications/%s/private/templates" % session.appname
        dir_list = os.listdir(template_path)
        dir_list.sort()
        option_list = ""
        selected_template = get_000_config("template", "default")
        for file in dir_list:
            new_file = "%s/%s" % (template_path, file)
            if os.path.isdir(new_file):
                if file == selected_template:
                    option_list = option_list\
                                + OPTION(file,
                                         _id=file,
                                         _value=file,
                                         _selected=True).xml()
                else:
                    option_list = option_list\
                                + OPTION(file,
                                         _id=file,
                                         _value=file).xml()
        reply.template_options = option_list
        reply.dialog = "#template-form"
        reply.next = "template"
        (reply.html, reply.script) = template_dialog(app)
        return json.dumps(reply)

    def base_json(reply):
        sys_name = request.get_vars.sys_name
        sys_abbrv = request.get_vars.sys_abbrv
        sys_url = request.get_vars.sys_url
        if request.get_vars.debug:
            debug = True
        else:
            debug = False
        set_000_config("base.system_name", 'T("%s")' % sys_name)
        set_000_config("base.system_name_short", 'T("%s")' % sys_abbrv)
        set_000_config("base.public_url", '"%s"' % sys_url)
        set_000_config("base.debug", '%s' % debug)
        reply.detail = T("Details saved to 000_config file.",
                         lazy = False)
        reply.advanced = reply.detail +\
                        T("
System name %s" % (sys_name),
                          lazy = False) +\
                        T("
System abbreviation %s" % (sys_abbrv),
                          lazy = False)+\
                        T("
Public URL %s" % (sys_url),
                          lazy = False)
        if debug:
            reply.advanced = reply.advanced +\
                            T("
Debug setting turned on.",
                              lazy = False)
        return pre_template_json(reply)
    return base_json(reply)

def base_dialog(app):
    sys_name = get_000_config("system_name", "Sahana Eden Humanitarian Management Platform")
    sys_abbrv = get_000_config("system_name_short", "Sahana Eden")
    sys_url = get_000_config("public_url", "http://127.0.0.1:8000")
    debug = get_000_config("debug", True)
    base = DIV(_id="sys-base-form",
                  _title=T("Enter the system details")
                 )
    base.append(P(T("Provide base system details"),
                     _class="validateTips"))
    base.append(FORM(LABEL(T("System name")),
                        INPUT(_id = "sys_name_in",
                              _name = "sys_name_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = sys_name
                             ),
                        LABEL(T("System short name")),
                        INPUT(_id = "sys_abbrv_in",
                              _name = "sys_abbrv_in",
                              _class="text ui-widget-content ui-corner-all",
                              value = sys_abbrv
                             ),
                        LABEL(T("Public URL")),
                        INPUT(_id = "url_in",
                              _name = "url_in",
                              _class="text ui-widget-content ui-corner-all",
                              _value = sys_url
                             ),
                        LABEL(T("Debug Mode (Developer only)")),
                        INPUT(_id = "debug_in",
                              _name = "debug_in",
                              _type = "checkbox",
                              _value = "debug",
                              _checked = debug,
                              _class="text ui-widget-content ui-corner-all"
                             )
                        )
                   )
    script = "static/js/base.js"
    return (base.xml(), script)

def template():
    def template_json(reply):
        selected_template = request.get_vars.template
        set_000_config("base.template", '"%s"' % selected_template)
        reply.dialog = "#module-form"
        reply.next = "module"
        reply.detail = T("Template %s selected." % selected_template,
                         lazy = False)
        session.template = selected_template
        (reply.html, reply.script) = module_dialog(app)
        return json.dumps(reply)
    return template_json(reply)

def template_dialog(app):
    template = DIV(_id="template-form",
                  _title=T("Template")
                 )
    template.append(P(T("Select the template that will be used.")))
    template.append(TABLE(TR(TD( LABEL(T("Template"))),
                             TD( SELECT(_id = "template_in",
                                        _name = "template_in"
                                       )
                                )
                              )
                        )
                   )
    script = "static/js/template.js"
    return (template.xml(), script)

def module_dialog(app):
    import sys
    appname = session.appname
    # Code to get a list of modules
    base_path = os.path.join("applications", appname)
    path = os.path.join(base_path, "modules", "s3")
    sys.path.append(path)
    try:
        from s3translate import TranslateGetFiles, TranslateAPI
    except:
        print "Failed to import s3translate base_path=%s path=%s" % (base_path, path)
    modlist = TranslateGetFiles.get_module_list(base_path)
    corelist = TranslateAPI.core_modules
    def get_template_modules():
        path = os.path.join(base_path, "modules")
        sys.path.append(path)
        from s3cfg import S3Config
        from gluon.storage import Storage
        from gluon import current
        current.deployment_settings = S3Config()
        template_path = os.path.join(base_path, "private", "templates", session.template)
        config_file = os.path.join(template_path,"config.py")
        # If the selected template doesn't have a config.py file then copy
        # the file from the default template.
        if not os.path.exists(config_file):
            from shutil import copy
            default_config = os.path.join(base_path,
                                          "private",
                                          "templates",
                                          "default",
                                          "config.py"
                                          )
            copy(default_config, config_file)
        sys.path.append(template_path)
        import config
        return config.settings.modules.keys()

    def get_module_nice_name(mod):
        data = read_config_file(session.appname, session.template)
        quoted_mod = '"%s"' % mod
        started = False
        module_found = False
        for line in data:
            if "settings.modules" in line:
                started = True
            if not started:
                continue
            if  quoted_mod in line:
                module_found = True
            if module_found and "name_nice" in line:
                start_line = False
                nice_name = ""
                for char in line:
                    if start_line and char == '"':
                        start_line = False
                    elif char == '"':
                        start_line = True
                        continue
                    if start_line:
                        nice_name += char
                return nice_name
        return mod

    templatelist = get_template_modules()
    module = DIV(_id="module-form",
                  _title=T("Template")
                 )
    module.append(P(T("Select the modules that will be enabled.")))
    colcnt = 4
    ctable = TABLE(TR(TD(H2(T("Core Modules")),
                        _colspan = 2*colcnt
                       )
                    ),
                    _id="module_list"
                 )
    ctr = TR()
    ctable.append(ctr)
    ccol = 0
    otable = TABLE(TR(TD(H2(T("Other Modules")),
                        _colspan = 2*colcnt
                       )
                    ),
                    _id="module_list"
                 )
    otr = TR()
    otable.append(otr)
    ocol = 0
    modlist.sort()
    templatelist.sort()
    for mod in modlist:
        nice_name = get_module_nice_name(mod)
        coremod = False
        if mod in corelist:
            coremod = True
        if not coremod and mod in templatelist:
            continue
        cb_name = "%s_in" % mod
        input = INPUT(_id = cb_name,
                      _name = cb_name,
                      _type = "checkbox",
                      _value = mod,
                      _checked = True,
                      _class="text ui-widget-content ui-corner-all"
                     )
        td = TD(input)
        if coremod:
            input.attributes["_disabled"]="disabled"
            ctr.append(td)
            ctr.append(TD(LABEL(nice_name)))
            ccol = (ccol + 1) % colcnt
            if ccol == 0:
                ctr = TR()
                ctable.append(ctr)
        else:
            input.attributes["_checked"]=False
            otr.append(td)
            otr.append(TD(LABEL(nice_name)))
            ocol = (ocol + 1) % colcnt
            if ocol == 0:
                otr = TR()
                otable.append(otr)
    ttable = TABLE(TR(TD(H2(T("Template Modules")),
                        _colspan = 2*colcnt
                       )
                    ),
                    _id="module_list"
                 )
    ttr = TR()
    ttable.append(ttr)
    tcol = 0
    for mod in templatelist:
        if mod in corelist:
            continue
        nice_name = get_module_nice_name(mod)
        cb_name = "%s_in" % mod
        input = INPUT(_id = cb_name,
                      _name = cb_name,
                      _type = "checkbox",
                      _value = mod,
                      _checked = True,
                      _class="text ui-widget-content ui-corner-all"
                     )
        td = TD(input)
        ttr.append(td)
        ttr.append(TD(LABEL(nice_name)))
        tcol = (tcol + 1) % colcnt
        if tcol == 0:
            ttr = TR()
            ttable.append(ttr)
    module.append(ctable)
    module.append(ttable)
    module.append(otable)
    script = "static/js/module.js"
    return (module.xml(), script)

def module():
    def commented(line):
        for char in line:
            if char == " ":
                continue
            return char == "#"

    def enable_module(mod):
        data = read_config_file(session.appname, session.template)
        quoted_mod = '"%s"' % mod
        uncomment = False
        started = False
        new_data = ""
        for line in data:
            if "settings.modules" in line:
                started = True
            if not started:
                new_data += line
                continue
            if quoted_mod in line and commented(line):
                uncomment = True
            if uncomment:
                new_line = ""
                start_line = True
                for char in line:
                    if start_line  and char == "#":
                        continue
                    if char == " ":
                        new_line += " "
                    else:
                        new_line += char
                        start_line = False
                new_data += new_line
            else:
                new_data += line
            if "))," in line:
                uncomment = False

        with open(base_cfg_file, 'w') as file:
            file.writelines( new_data )

    def disable_module(mod):
        data = read_config_file(session.appname, session.template)
        quoted_mod = '"%s"' % mod
        to_comment = False
        started = False
        new_data = ""
        for line in data:
            if "settings.modules" in line:
                started = True
            if not started:
                new_data += line
                continue
            if quoted_mod in line and not commented(line):
                to_comment = True
            if to_comment:
                new_data += "#%s" % line
            else:
                new_data += line
            if "))," in line:
                to_comment = False

        with open(base_cfg_file, 'w') as file:
            file.writelines( new_data )

    enabled_modules = json.loads(request.get_vars.module)['enabled']
    disabled_modules = json.loads(request.get_vars.module)['disabled']
    for mod in enabled_modules:
        enable_module(mod)
    for mod in disabled_modules:
        disable_module(mod)

    def module_json(reply):
        set_000_config("FINISHED_EDITING_CONFIG_FILE", "", True)
        reply.next = "finished"
        return json.dumps(reply)
    return module_json(reply)


text:
/**
 * Support and FAQ: visit Atmel Support
 */

#ifndef _USB_SPECIFIC_REQUEST_H_
#define _USB_SPECIFIC_REQUEST_H_

//_____ I N C L U D E S ____________________________________________________

#include "conf_usb.h"

#if USB_DEVICE_FEATURE == false
  #error usb_specific_request.h is #included although USB_DEVICE_FEATURE is disabled
#endif

#include "hid.h"

//_____ M A C R O S ________________________________________________________

//_____ D E F I N I T I O N S ______________________________________________

extern const S_usb_device_descriptor usb_dev_desc;
extern const S_usb_device_qualifier_descriptor usb_qualifier_desc;
extern const S_usb_user_configuration_descriptor usb_conf_desc_fs;
extern const S_usb_user_configuration_descriptor usb_conf_desc_hs;
extern const S_usb_manufacturer_string_descriptor usb_user_manufacturer_string_descriptor;
extern const S_usb_product_string_descriptor usb_user_product_string_descriptor;
extern const S_usb_serial_number usb_user_serial_number;
extern const S_usb_language_id usb_user_language_id;

#define USB_HID_REPORT_DESC 53
extern const U8 usb_hid_report_descriptor [USB_HID_REPORT_DESC];

//! @defgroup specific_request USB device specific requests
//! @{

//! @brief This function configures the endpoints of the device application.
//! This function is called when the set configuration request has been received.
//!
//! The core of this function should be correctly rewritten depending on the USB device
//! application characteristics (the USB device application has specific endpoint
//! configuration).
//!
extern void usb_user_endpoint_init(U8);

//! This function is called by the standard USB read request function when
//! the USB request is not supported. This function returns true when the
//! request is processed. This function returns false if the request is not
//! supported. In this case, a STALL handshake will be automatically
//! sent by the standard USB read request function.
//!
extern bool usb_user_read_request(U8, U8);
extern bool usb_user_get_descriptor(U8, U8);

extern void usb_hid_set_report_feature(void);

//! @}

#endif  // _USB_SPECIFIC_REQUEST_H_

redpajama_set_name: RedPajamaGithub


text:
Spree Historical Report
=====================

This gem allows Spree to store and generate a simple report of the SKU and the date when a products is out of stock.

## Demo

A demo is available at http://spree-historical-report.herokuapp.com

The historical report is in the administration backend, in the report section, under historical report

  ```
    user: spree@example.com
    pass: spree123
  ```

## Installation

1. Add this extension to your Gemfile with this line:
  ```ruby
  gem 'spree_historical_report', github: 'tpgunther/spree_historical_report', branch: '3-1-stable'
  ```

2. Install the gem using Bundler:
  ```ruby
  bundle install
  ```

3. Copy & run migrations
  ```ruby
  bundle exec rails g spree_historical_report:install
  ```

4. Restart your server

  If your server was running, restart it so that it can find the assets properly.

## Testing

First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs. The dummy app can be regenerated by using `rake test_app`.

  ```shell
  bundle
  bundle exec rake
  ```

Copyright (c) 2016 Tomás Günther, released under the New BSD License


text:
"""
Base Django settings for sandbox
"""
import os

BASE_DIR = os.path.join(
    os.path.dirname(os.path.abspath(__file__)),
    "..",
)
DATA_DIR = os.path.join(BASE_DIR, "..", "data")

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'cLiI!d*X=(%#?HyW]0!v"T-DFRk>JaukodHalf]&BLO5qkwB}S-_2'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["*"]

# Application definition

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'sandbox.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'sandbox.wsgi.application'

# Database

DATABASES = {
    # Development default database engine use sqlite3
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(DATA_DIR, 'db', 'db.sqlite3'),
    }
}
MIGRATION_MODULES = {}

# Internationalization

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

# RemovedInDjango50Warning: The USE_L10N setting is deprecated. Starting with Django 5.0, localized formatting of data will always be enabled. For example Django will display numbers and dates using the format of the current locale.
#    warnings.warn(USE_L10N_DEPRECATED_MSG, RemovedInDjango50Warning)
# USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)

STATIC_URL = '/static/'

"""
NOTE:
    * Every things above comes from default generated settings file (from Django startproject);
    * Every things below are needed settings for sandbox;
    * Don't edit default generated settings, instead override them below;
"""

# Absolute filesystem path to the directory that contain tests fixtures files
TESTS_FIXTURES_DIR = os.path.join('..', 'tests', 'data_fixtures')

INSTALLED_APPS = INSTALLED_APPS+(
    'crispy_forms',
    'crispy_forms_foundation',
    'sandbox.demo',
)

# Absolute filesystem path to the directory that will hold user-uploaded files.
MEDIA_ROOT = os.path.join(DATA_DIR, "media")

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
MEDIA_URL = '/media/'

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
STATIC_ROOT = os.path.join(DATA_DIR, "static")

STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)

# Template dir
TEMPLATES[0]['DIRS'] = (os.path.join(BASE_DIR, "templates"),)


text:
function tagHeadHTML( analyticsID ) {
	return `

	`;
}

/**
 * Generates valid HTML with an Analytics tag.
 *
 * @since 1.13.0
 *
 * @param {string} analyticsID Analytics ID to generate tag with.
 * @return {string} HTML.
 */
export function generateHTMLWithTag( analyticsID ) {
	return `
		<!DOCTYPE html>

				${ analyticsID && tagHeadHTML( analyticsID ) }
				<title>Test Title</title>

Test Title

	`;
}


text:
<?php

namespace Liip\ImagineBundle\Tests;

use Imagine\Image\ImageInterface;
use Imagine\Image\ImagineInterface;
use Imagine\Image\Metadata\MetadataBag;
use Liip\ImagineBundle\Binary\Loader\LoaderInterface;
use Liip\ImagineBundle\Binary\MimeTypeGuesserInterface;
use Liip\ImagineBundle\Config\Controller\ControllerConfig;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Liip\ImagineBundle\Imagine\Cache\Resolver\ResolverInterface;
use Liip\ImagineBundle\Imagine\Cache\SignerInterface;
use Liip\ImagineBundle\Imagine\Data\DataManager;
use Liip\ImagineBundle\Imagine\Filter\FilterConfiguration;
use Liip\ImagineBundle\Imagine\Filter\FilterManager;
use Liip\ImagineBundle\Imagine\Filter\PostProcessor\PostProcessorInterface;
use Liip\ImagineBundle\Service\FilterService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesserInterface;
use Symfony\Component\Mime\MimeTypesInterface;
use Symfony\Component\Routing\RouterInterface;

abstract class AbstractTest extends TestCase
{
    /**
     * @var Filesystem
     */
    protected $filesystem;

    /**
     * @var string
     */
    protected $fixturesPath;

    /**
     * @var string
     */
    protected $temporaryPath;

    protected function setUp(): void
    {
        $this->fixturesPath = realpath(__DIR__.DIRECTORY_SEPARATOR.'Fixtures');
        $this->temporaryPath = sys_get_temp_dir().DIRECTORY_SEPARATOR.'liip_imagine_test';
        $this->filesystem = new Filesystem();

        if ($this->filesystem->exists($this->temporaryPath)) {
            $this->filesystem->remove($this->temporaryPath);
        }

        $this->filesystem->mkdir($this->temporaryPath);
    }

    protected function tearDown(): void
    {
        if (!$this->filesystem) {
            return;
        }

        if ($this->filesystem->exists($this->temporaryPath)) {
            $this->filesystem->remove($this->temporaryPath);
        }
    }

    /**
     * @return string[]
     */
    public function invalidPathProvider(): array
    {
        return [
            [$this->fixturesPath.'/assets/../../foobar.png'],
            [$this->fixturesPath.'/assets/some_folder/../foobar.png'],
            ['../../outside/foobar.jpg'],
        ];
    }

    public function expectExceptionMessageMatchesBC(string $regularExpression): void
    {
        if (method_exists($this, 'expectExceptionMessageMatches')) {
            $this->expectExceptionMessageMatches($regularExpression);
        } else {
            $this->expectExceptionMessageRegExp($regularExpression);
        }
    }

    protected function createFilterConfiguration(): FilterConfiguration
    {
        $config = new FilterConfiguration();
        $config->set('thumbnail', [
            'size' => [180, 180],
            'mode' => 'outbound',
        ]);

        return $config;
    }

    /**
     * @return MockObject|CacheManager
     */
    protected function createCacheManagerMock()
    {
        return $this
            ->getMockBuilder(CacheManager::class)
            ->setConstructorArgs([
                $this->createFilterConfiguration(),
                $this->createRouterInterfaceMock(),
                $this->createSignerInterfaceMock(),
                $this->createEventDispatcherInterfaceMock(),
            ])
            ->getMock();
    }

    /**
     * @return MockObject|FilterConfiguration
     */
    protected function createFilterConfigurationMock()
    {
        return $this->createObjectMock(FilterConfiguration::class);
    }

    /**
     * @return MockObject|SignerInterface
     */
    protected function createSignerInterfaceMock()
    {
        return $this->createObjectMock(SignerInterface::class);
    }

    /**
     * @return MockObject|RouterInterface
     */
    protected function createRouterInterfaceMock()
    {
        return $this->createObjectMock(RouterInterface::class);
    }

    /**
     * @return MockObject|ResolverInterface
     */
    protected function createCacheResolverInterfaceMock()
    {
        return $this->createObjectMock(ResolverInterface::class);
    }

    /**
     * @return MockObject|EventDispatcherInterface
     */
    protected function createEventDispatcherInterfaceMock()
    {
        return $this->createObjectMock(EventDispatcherInterface::class);
    }

    /**
     * @return MockObject|ImageInterface
     */
    protected function getImageInterfaceMock()
    {
        return $this->createObjectMock(ImageInterface::class);
    }

    /**
     * @return MockObject|MetadataBag
     */
    protected function getMetadataBagMock()
    {
        return $this->createObjectMock(MetadataBag::class);
    }

    /**
     * @return MockObject|ImagineInterface
     */
    protected function createImagineInterfaceMock()
    {
        return $this->createObjectMock(ImagineInterface::class);
    }

    /**
     * @return MockObject|LoggerInterface
     */
    protected function createLoggerInterfaceMock()
    {
        return $this->createObjectMock(LoggerInterface::class);
    }

    /**
     * @return MockObject|LoaderInterface
     */
    protected function createBinaryLoaderInterfaceMock()
    {
        return $this->createObjectMock(LoaderInterface::class);
    }

    /**
     * @return MockObject|MimeTypeGuesserInterface
     */
    protected function createMimeTypeGuesserInterfaceMock()
    {
        return $this->createObjectMock(MimeTypeGuesserInterface::class);
    }

    /**
     * @return MockObject|ExtensionGuesserInterface
     */
    protected function createExtensionGuesserInterfaceMock()
    {
        if (!interface_exists(MimeTypesInterface::class)) {
            return $this->createObjectMock(ExtensionGuesserInterface::class);
        }

        return $this->createObjectMock(MimeTypesInterface::class);
    }

    /**
     * @return MockObject|PostProcessorInterface
     */
    protected function createPostProcessorInterfaceMock()
    {
        return $this->createObjectMock(PostProcessorInterface::class);
    }

    /**
     * @return MockObject|FilterManager
     */
    protected function createFilterManagerMock()
    {
        return $this->createObjectMock(FilterManager::class, [], false);
    }

    /**
     * @return MockObject|FilterService
     */
    protected function createFilterServiceMock()
    {
        return $this->createObjectMock(FilterService::class);
    }

    /**
     * @return MockObject|DataManager
     */
    protected function createDataManagerMock()
    {
        return $this->createObjectMock(DataManager::class, [], false);
    }

    protected function createControllerConfigInstance(int $redirectResponseCode = null): ControllerConfig
    {
        return new ControllerConfig($redirectResponseCode ?? 301);
    }

    /**
     * @param string[] $methods
     * @param mixed[]  $constructorParams
     */
    protected function createObjectMock(string $object, array $methods = [], bool $constructorInvoke = false, array $constructorParams = []): MockObject
    {
        $builder = $this->getMockBuilder($object);

        if (\count($methods) > 0) {
            $builder->setMethods($methods);
        }

        if ($constructorInvoke) {
            $builder->enableOriginalConstructor();
        } else {
            $builder->disableOriginalConstructor();
        }

        if (\count($constructorParams) > 0) {
            $builder->setConstructorArgs($constructorParams);
        }

        return $builder->getMock();
    }

    /**
     * @param object $object
     */
    protected function getVisibilityRestrictedMethod($object, string $name): \ReflectionMethod
    {
        $r = new \ReflectionObject($object);

        $m = $r->getMethod($name);
        $m->setAccessible(true);

        return $m;
    }
}


text:
from __future__ import print_function
import numpy as np
import cv2
import time
import requests
import operator

# Variables

_url = 'https://api.projectoxford.ai/vision/v1.0/analyze'
_key = 'e80f8ece393f4eebb3d98b0bb36f04d0'
_maxNumRetries = 10

def processRequest( json, data, headers, params ):

    """
    Helper function to process the request to Project Oxford

    Parameters:
    json: Used when processing images from its URL. See API Documentation
    data: Used when processing image read from disk. See API Documentation
    headers: Used to pass the key information and the data type request
    """

    retries = 0
    result = None

    while True:
        response = requests.request( 'post', _url, json = json, data = data, headers = headers, params = params )
        print ("uuuuhhhhh %s", response.status_code)
        if response.status_code == 429:

            print( "Message: %s" % ( response.json()['error']['message'] ) )

            if retries <= _maxNumRetries:
                time.sleep(1)
                retries += 1
                continue
            else:
                print( 'Error: failed after retrying!' )
                break

        elif response.status_code == 200 or response.status_code == 201:

            if 'content-length' in response.headers and int(response.headers['content-length']) == 0:
                result = None
            elif 'content-type' in response.headers and isinstance(response.headers['content-type'], str):
                if 'application/json' in response.headers['content-type'].lower():
                    result = response.json() if response.content else None
                elif 'image' in response.headers['content-type'].lower():
                    result = response.content
        else:
            print( "Error code: %d" % ( response.status_code ) )
            print( "Message: %s" % ( response.json()['error']['message'] ) )

        break

    return result

def renderResultOnImage( result, img ):

    """Display the obtained results onto the input image"""

    R = int(result['color']['accentColor'][:2],16)
    G = int(result['color']['accentColor'][2:4],16)
    B = int(result['color']['accentColor'][4:],16)

    cv2.rectangle( img,(0,0), (img.shape[1], img.shape[0]), color = (R,G,B), thickness = 25 )

    if 'categories' in result:
        categoryName = sorted(result['categories'], key=lambda x: x['score'])[0]['name']
        cv2.putText( img, categoryName, (30,70), cv2.FONT_HERSHEY_SIMPLEX, 2, (255,0,0), 3 )


text:
<?xml version="1.0" encoding="utf-8"?>

<!-- Generated with http://android-holo-colors.com -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">

  <style name="AppTheme" parent="android:Theme.Light">

  </style>

</resources>


text:
ACCEPTED

#### According to
Index Fungorum

#### Published in
Mycopath. Mycol. appl. 7: 87 (1954)

#### Original name
Irenina ebuli W. Yamam.

### Remarks
null


text:
from .models import Measurement as MeasurementObject, UnitMeasurementException
from .models import Unit as UnitObject
from .ConglomerateWidgets import UnitEntryField, SingleMeasurementEntryFieldStack, MeasurementEntryGridField
from .MeasurementWidgets import UnitDisplay, UnitComboBox, UnitSpinBox
from .UnitComboDelegate import UnitComboDelegate
from .CurrentUnitSetter import setter as _setter
from . import SelectionMenu

_measurements = {}

def menu(parent, measurements=None):
    if measurements is None:
        #only those measurements which have been used for something
        return SelectionMenu.menu(_measurements.values(),parent)
    else:
        return SelectionMenu.menu([m for m in measurements if m in _measurements.values()], parent)

def Measurement(name):
    """
    :type name: str
    :rtype: MeasurementObject
    :raises UnitMeasurementException
    """
    if name not in _measurements:
        _measurements[name] = MeasurementObject(name)
    return _measurements[name]

def Unit(measurement, name):
    """
    :type measurement: MeasurementObject
    :type name: str
    :rtype: UnitObject
    :raises UnitMeasurementException
    """
    for u in measurement.units:
        if u.name == name:
            return u
    for u in measurement.units:
        if name in u.alias():
            return u
    raise UnitMeasurementException("There is no unit for " + str(measurement) + " by the name: " + name)

def changedSignal():
    """
    :rtype: callable
    """
    return _setter.changed

def measurements_list():
    return('Length','Angle','Pressure','Temperature','Volume', 'Mass', 'Proportion', 'Density', 'Force', 'Power', 'Time', 'AngularSpeed', 'Torque', 'None', 'Speed', 'Inertia', 'Area', 'Current', 'Voltage', 'Magnetic Flux Linkage', 'Flux Density', 'Inductance', 'Resistance', 'Current Density', 'Torque Per Unit Current', 'Voltage Per Unit AngularSpeed')


text:
class File

  SUBTITLES_FILETYPES = ['txt', 'srt']

  def self.has_subtitles?(f)
    SUBTITLES_FILETYPES.any? { |sub_ext|
      subs_filename = File.join(File.dirname(f), File.basename(f, '.*') + '.' + sub_ext)
      File.exists?(subs_filename)
    }
  end

end

module Subchk

  class MissingSubtitlesDownloader

    VIDEO_FILETYPES = ['mkv', 'avi', 'mp4']

    def initialize(dir, notifier)
      @dir = dir
      @notifier = notifier
    end

    def collect_video_files
      VIDEO_FILETYPES.map { |video_ftype| Dir.glob(@dir + '/**/*.' + video_ftype) }.flatten
    end

    def collect_video_files_without_subtitles
      collect_video_files.select do |f|
        !File.has_subtitles?(f)
      end
    end

    def download_missing_subtitles
      collect_video_files_without_subtitles.each do |f|
        cmd = "qnapi -q \"#{f}\""
        result = system(cmd)

        if result and File.has_subtitles?(f)
          short = File.basename(f)
          @notifier.notify "Subs downloaded: #{short}", "Successfully downloaded subtitles for #{short}."
        end
      end
    end

  end
end


text:
namespace Server.WonderMails
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    using DataManager.Players;

    using Server.Players;

    public class WonderMailJob
    {
        #region Fields

        WonderMail mission;

        #endregion Fields

        #region Constructors

        public WonderMailJob(PlayerDataJobListItem baseJobItem) {

            mission = new WonderMail(baseJobItem);
        }

        public WonderMailJob(WonderMail mail) {
            mission = mail;
        }

        public WonderMailJob(WonderMailJob mail) {
            mission = new WonderMail(new PlayerDataJobListItem());
            mission.Data1 = mail.Mission.Data1;
            mission.Data2 = mail.Mission.Data2;
            mission.Difficulty = mail.Mission.Difficulty;
            mission.DungeonIndex = mail.Mission.DungeonIndex;
            mission.DungeonMapNum = mail.Mission.DungeonMapNum;
            mission.GoalMapIndex = mail.Mission.GoalMapIndex;
            mission.GoalName = mail.Mission.GoalName;
            mission.LoseStoryScript = mail.Mission.LoseStoryScript;
            mission.MissionClientIndex = mail.Mission.MissionClientIndex;
            mission.MissionType = mail.Mission.MissionType;
            mission.Mugshot = mail.Mission.Mugshot;
            mission.RDungeon = mail.Mission.RDungeon;
            mission.RDungeonFloor = mail.Mission.RDungeonFloor;
            mission.RewardIndex = mail.Mission.RewardIndex;
            mission.StartStoryScript = mail.Mission.StartStoryScript;
            mission.Summary = mail.Mission.Summary;
            mission.TargetIndex = mail.Mission.TargetIndex;
            mission.Title = mail.Mission.Title;
            mission.WinStoryScript = mail.Mission.WinStoryScript;
        }

        #endregion Constructors

        #region Properties

        public Enums.JobStatus Accepted {
            get { return (Enums.JobStatus)mission.RawMission.Accepted; }
            set { mission.RawMission.Accepted = (int)value; }
        }

        public PlayerDataJobListItem RawJob {
            get { return mission.RawMission; }
        }

        public int SendsRemaining {
            get { return mission.RawMission.SendsRemaining; }
            set { mission.RawMission.SendsRemaining = value; }
        }

        public WonderMail Mission {
            get { return mission; }
        }

        #endregion Properties
    }
}


text:
"""
    nextversion
    ~~~~~~~~~~~

    Increments module verision numbers.::

        from nextversion import nextversion
        nextversion('1.0a2')    # => '1.0a3'
        nextversion('v1.0a2')   # => '1.0a3'  (normalized to compatible version with PEP 386)
        nextversion('foo.0.3')  # => None     (impossible to normalize)

    If original version number does not match `PEP 386 <//www.python.org/dev/peps/pep-0386/>`_ ,

    1. Next version compatible with `PEP 386 <//www.python.org/dev/peps/pep-0386/>`_ is returned if possible,
    2. If impossible, `None` is returned.
"""
import verlib

def nextversion(current_version):
    """Returns incremented module version number.

    :param current_version: version string to increment
    :returns:               Next version string (PEP 386 compatible) if possible.
                            If impossible (since `current_version` is too far from PEP 386),
                            `None` is returned.
    """
    norm_ver = verlib.suggest_normalized_version(current_version)
    if norm_ver is None:
        return None
    norm_ver = verlib.NormalizedVersion(norm_ver)

    # increment last version figure
    parts = norm_ver.parts   # see comments of `verlib.py` to get the idea of `parts`
    assert(len(parts) == 3)
    if len(parts[2]) > 1:    # postdev
        if parts[2][-1] == 'f':  # when `post` exists but `dev` doesn't
            parts = _mk_incremented_parts(parts, part_idx=2, in_part_idx=-2, incval=1)
        else:                    # when both `post` and `dev` exist
            parts = _mk_incremented_parts(parts, part_idx=2, in_part_idx=-1, incval=1)
    elif len(parts[1]) > 1:  # prerel
        parts = _mk_incremented_parts(parts, part_idx=1, in_part_idx=-1, incval=1)
    else:                    # version & extraversion
        parts = _mk_incremented_parts(parts, part_idx=0, in_part_idx=-1, incval=1)
    norm_ver.parts = parts

    return str(norm_ver)

def _mk_incremented_parts(parts, part_idx, in_part_idx, incval=1):
    in_part_idx %= len(parts[part_idx])  # for negative index

    new_part = []
    for i, e in enumerate(parts[part_idx]):
        new_part.append(e + incval if i == in_part_idx else e)

    # workaround for bug in verlib.NormalizedVersion.parts_to_str
    if new_part[-1] == verlib.FINAL_MARKER[0]:
        new_part.pop()

    new_part = tuple(new_part)

    new_parts = []
    for i, part in enumerate(parts):
        new_parts.append(new_part if i == part_idx else part)
    return tuple(new_parts)


text:
AddCSLuaFile()
DEFINE_BASECLASS( "base_wire_entity" )
ENT.PrintName       = "Wire Nailer"
ENT.RenderGroup		= RENDERGROUP_BOTH
ENT.WireDebugName	= "Nailer"

function ENT:SetupDataTables()
	self:NetworkVar( "Float", 0, "BeamLength" )
	self:NetworkVar( "Bool",  0, "ShowBeam" )
end

if CLIENT then return end -- No more client

function ENT:Initialize()
	self:PhysicsInit( SOLID_VPHYSICS )
	self:SetMoveType( MOVETYPE_VPHYSICS )
	self:SetSolid( SOLID_VPHYSICS )
	self.Inputs = WireLib.CreateInputs(self, { "Weld", "Axis", "Ballsocket" })
	self:SetBeamLength(2048)
end

function ENT:Setup(flim, Range, ShowBeam)
	self.Flim = math.Clamp(flim, 0, 10000)
	if Range then self:SetBeamLength(Range) end
	if ShowBeam ~= nil then self:SetShowBeam(ShowBeam) end
	self:ShowOutput()
end

function ENT:CanNail(trace)
	-- Bail if we hit world or a player
	if not IsValid(trace.Entity) or trace.Entity:IsPlayer() then return false end
	-- If there's no physics object then we can't constraint it!
	if not util.IsValidPhysicsObject(trace.Entity, trace.PhysicsBone) then return false end
	-- The nailer tool no longer exists, but we ask for permission under its name anyway
	if hook.Run( "CanTool", self:GetPlayer(), trace, "nailer" ) == false then return false end
	return true
end

function ENT:TriggerInput(name, value)
	if value == 0 then return end

	local up = self:GetUp()

	local trace1 = util.TraceLine( {
		start = self:GetPos(),
		endpos = self:GetPos() + up * self:GetBeamLength(),
		filter = { self }
	} )

	if not self:CanNail( trace1 ) then return end

	local trace2 = util.TraceLine( {
		start = trace1.HitPos,
		endpos = trace1.HitPos + up * 50,
		filter = { trace1.Entity, self }
	} )

	if not self:CanNail( trace2 ) then return end

	if name == "Weld" then
		constraint.Weld( 	trace1.Entity,
							trace2.Entity,
							trace1.PhysicsBone,
							trace2.PhysicsBone,
							self.Flim
						)
	elseif name == "Axis" then
		local phys1 = trace1.Entity:GetPhysicsObject()
		local phys2 = trace2.Entity:GetPhysicsObject()
		if not IsValid( phys1 ) or not IsValid( phys2 ) then return end

		local LPos1 = phys1:WorldToLocal( trace2.HitPos + trace2.HitNormal )
		local LPos2 = phys2:WorldToLocal( trace2.HitPos )

		constraint.Axis(	trace1.Entity,
							trace2.Entity,
							trace1.PhysicsBone,
							trace2.PhysicsBone,
							LPos1, LPos2,
							self.Flim
						)
	elseif name == "Ballsocket" then
		constraint.Ballsocket(	trace1.Entity,
								trace2.Entity,
								trace1.PhysicsBone,
								trace2.PhysicsBone,
								trace2.Entity:WorldToLocal(trace1.HitPos),
								self.Flim
							)
	end

	-- effect on weld (tomb332)
	local effectdata = EffectData()
		effectdata:SetOrigin( trace2.HitPos )
		effectdata:SetNormal( trace1.HitNormal )
		effectdata:SetMagnitude( 5 )
		effectdata:SetScale( 1 )
		effectdata:SetRadius( 10 )
	util.Effect( "Sparks", effectdata, false, true )
end

function ENT:ShowOutput()
	self:SetOverlayText(string.format( "Range: %s\nForce limit: %s", math.Round(self:GetBeamLength(),2), math.Round(self.Flim,2) ))
end

WireLib.AddInputAlias( "A", "Weld" )

duplicator.RegisterEntityClass("gmod_wire_nailer", WireLib.MakeWireEnt, "Data", "Flim", "Range", "ShowBeam")


text:
package mainWorkbook;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;

public class HomePage implements IPage {

	private ArrayList<Person> family = new ArrayList<Person>();
	private static String[] help = {"exit", "goto garden", "add person", "delete person", "display", "whereami"};

	private String pageName;
	Scanner sc = new Scanner(System.in);

	public HomePage(String name){
		pageName = name;
	}

	//supporter methods (not called from start() )

	private int findPerson(String name) throws PersonNotFoundException {

		for (int i = 0; i < family.size(); i++){
			Person curPerson = family.get(i);

			if (curPerson.getName().equals(name)){
				return i;
			}

		}
		throw new PersonNotFoundException("This person could not be found in your family");
	}

	//Methods called from start()

	private void addPerson(){
		// get the values required for the new person
		//add them to the family

		System.out.println("What is their name?");
		String name = sc.nextLine().toLowerCase();

		boolean inputGood = false;
		PersonType type = null;
		while (!inputGood){
			int num = getInt("What type of is it?\n"
					+ "(Type '1' child aged 1-6, '2' child aged 7-12,\n"
					+ " '3' for female aged 13-19, '4' male aged 13-19, '5' for nursing woman, '6' for female 20+, '7' for male 20+");

			switch (num){
			case 1 : type = PersonType.yChild; inputGood = true; break;
			case 2 : type = PersonType.oChild; inputGood = true; break;
			case 3 : type = PersonType.fTeen; inputGood = true;break;
			case 4 : type = PersonType.mTeen; inputGood = true; break;
			case 5 : type = PersonType.nursing; inputGood = true; break;
			case 6 : type = PersonType.fAdult; inputGood = true; break;
			case 7 :  type = PersonType.mAdult; inputGood = true; break;
			default : System.out.println ("Please enter a number that is between 1-7");
			}
		}

		Person newPerson = new Person(name, type);
		WorkbookGlobals.updateNeed(newPerson, UpdateType.add);

		family.add(newPerson);
	}

	private void deletePerson(){
		//find the person in the family,
		//then delete them

		System.out.println("What is the name of the person you want to delete?");
		String name = sc.nextLine().toLowerCase();

		try{
			int index = findPerson(name);
			WorkbookGlobals.updateNeed(family.get(index), UpdateType.delete);

			family.remove(index);

		}
		catch (PersonNotFoundException e){
			System.out.println(e.getMessage());
		}

	}

	public String displayPage() {
		// creates a string that can be outputted that shows
		//all the family members and their needs
		//total needed
		//total produced
		String returnString = "Family\n";

		for (Person x : family){
			returnString += x.toString();
		}

		returnString += WorkbookGlobals.getStringNeed() + WorkbookGlobals.getStringStillNeeded();

		return returnString;
	}

	//methods called from other classes

	public String start() {
		// main method for the HomePage
		//displays the page, allows user to
		//add or delete a person
		//returns if user asks to go to another page (returns the user's input)

		String input = "k";

		System.out.println(displayPage());

		while (!input.equals("exit")){ //had to do this instead of true to stop eclipse from complaining

			System.out.println("What do you want to do?");
			input = sc.nextLine().toLowerCase();

			switch(input){
				case "exit" : sc.close(); System.exit(0);

				case "goto garden" :  break;

				case "add person" : addPerson(); break;

				case "delete person" : deletePerson(); break;

				case "display" : System.out.println(displayPage()); break;

				case "whereami" : System.out.println(pageName); break;

				case "help" : help(); break;

			}

			if (input.equals("goto garden")){
				break;
			}

		}

		return input;
	}

	@Override
	public void help() {
		// list all commands possible
		System.out.println("Commands for Home Page\nCommands must be exactly as shown.\n");
		for (String s: help){
			System.out.println(s);
		}

	}

	private int getInt( String msg){
		//gets an number from the user
		boolean inputGood = false;
		int num = -1;
		System.out.println(msg);
		while (!inputGood){
			try{
				String stringNum = sc.nextLine();
				num = Integer.parseInt(stringNum);
				inputGood = true;
			}
			catch (NumberFormatException e){
				System.out.println("Please input a number");
			}
		}

		return num;
	}

	@Override
	public void savePage(Path filename) {
		//saves all the important home page info in a separate file
		String fileNameString = "HomePage_" + this.pageName + ".txt";
		Path curPath = filename.resolve(fileNameString);

		//Create file using example code from
		//http://docs.oracle.com/javase/tutorial/essential/io/file.html#creating
		try {
		    // Create the empty file with default permissions, etc.
		    Files.createFile(curPath);
		} catch (FileAlreadyExistsException x) {
		    System.err.format("file named %s" +
		        " already exists%n", curPath);
		} catch (IOException x) {
		    // Some other sort of failure, such as permissions.
		    System.err.format("createFile error: %s%n", x);
		}

		Charset charset = Charset.forName("US-ASCII");

		try (BufferedWriter writer = Files.newBufferedWriter(curPath, charset)) {
		   //Write to the file using writer the info needed
			for (Person x : family){
				writer.write(x.getName() + "_" + x.getType().getName());
				writer.newLine();
			}

		} catch (IOException x) {
		    System.err.format("IOException: %s%n", x);
		}

	}

	@Override
	public void loadPage(Path filename) {
		//load from the file specified

		Charset charset = Charset.forName("US-ASCII");

		try (BufferedReader reader = Files.newBufferedReader(filename, charset)) {
			//Read from the file using reader
			String s = reader.readLine();
			while (s != null){
				family.add(new Person(s));
				s = reader.readLine();
			}

		} catch (IOException x) {
		    System.err.format("IOException: %s%n", x);
		}

	}

}