text:
"""
Module for converting ATS4 AppModel (http://ats4appmodel.sourceforge.net/) XML
models to TEMA lsts models

Module provides Kendo2Lsts class that is used to handle the conversion, and
the main function to use the converter.

"""

tool_description = """ATS4AppModel2Lsts is a tool used to convert ATS4 AppModel (http://ats4appmodel.sourceforge.net/) XML-based models to TEMA lsts-based models that are executable with the TEMA test engine. The tool can be used both for creating a direct conversion or by instrumenting it to transform the ATS4 System model into a task switcher, allowing concurrent testing of application models.

"""

from xml.dom import minidom
import os
import re
import sys
import shutil
import codecs
import optparse
import sys, traceback

import tema.lsts.lsts as lsts

import tema.ats4appmodel.lstsmodel as lstsmodel

from tema.ats4appmodel.kendomodel import *

class Kendo2Lsts:

    """
    ATS4 AppModel model converter class

    Uses kendomodel module to parse ATS4 AppModel xml-files and to create an
    object hierarhy from them.
    Uses lstsmodel module to convert kendo object hierachy to lsts model and
    to write the model to files.

    """

    def __init__(self):

        self.__kendoXMLParser = None
        self.__sysModelFile = None

    def readKendoModel(self, sysModelPath):

        self.__sysModelFile = sysModelPath
        self.__kendoXMLParser = KendoXMLParser(sysModelPath)
        return self.__kendoXMLParser.parseKendoModel()

    def printKendoModel(self):
        self.__kendoXMLParser.printKendoModel()

    def writeLstsModel(self, outputDir, create_taskswitcher, apps_only_ts, generateSleep, defaultSleep = True):

        output = outputDir
        if outputDir != "" and not outputDir.endswith(os.sep):
            output = output + os.sep

        lstsmodelname = output.split(os.sep)[-2]

        os.mkdir(output)
        os.mkdir(output + "rm" + os.sep)

        model_names = []

        products = self.__kendoXMLParser.getProducts()
        system_model = products[0]

        if create_taskswitcher:
            print "Creating TaskSwitcher...",
            converter = lstsmodel.LstsModelCreator(products[0],products)
            model = converter.convertToTaskSwitcher(apps_only_ts, lstsmodelname +"-GateModel")

            model_names.append("TaskSwitcher-" + lstsmodelname)
            self.__writeLsts(model,"TaskSwitcher-" + lstsmodelname, output)

            gate_model = converter.createGateModel(products[0])
            model_names.append(lstsmodelname +"-GateModel")
            print "done"
            print "Writing TaskSwitcher...",
            self.__writeLsts(gate_model, lstsmodelname +"-GateModel", output)
            print "done"
            #model_names.append(product.getName().replace(" ", "%20"))
            system_model = products.pop(0)

        for product in products:
            #TODO: if name not given use e.g. "product+id"
            #self.__writeLsts(product, output)
            print "Converting "+product.getName()+"...",
            converter = lstsmodel.LstsModelCreator(product, products)
            model = converter.convertProduct(create_taskswitcher, generateSleep, defaultSleep)
            print "done"

            modelName = lstsmodel.getModelName(product)
            print "Writing "+modelName+"...",
            self.__writeLsts(model, modelName, output)
            model_names.append(modelName)
            print "done"

        #Create variable models for flags
        print "Writing flag models...",
        self.__createFlagModels(output)

        for flag in self.__kendoXMLParser.getFlags():
            model_names.append("flagmodel_"+flag.getName())
        print "done"

        #Create empty -files for models ( no LaunchApps )
        #if not create_taskswitcher:
        #    for name in model_names:
        #        file = open(output + name + ".info", "w")
        #        file.close()

        #Create info files that contain the app_model name (Usually app-model name corresponds the launchApp name)
        for state in system_model.getStates():
            if state.getType() == "APP_MODEL":
                appname = state.getName()
                matcher = re.search("[aA]ppname:\\s*\"(\\w+)\"",state.getDescription())
                if matcher:
                    appName = matcher.group(1)

                file = open(output + lstsmodel.getModelName(state.getLinkedProduct()) + ".info", "w")
                file.write("APPLICATION: " + appname + "\n")
                for sub in state.getLinkedProduct().getSubModels():
                    file = open(output + lstsmodel.getModelName(sub) + ".info", "w")
                    file.write("APPLICATION: " + appname + "\n")
                file.close()

        print "Generating Makefile...",
        self.__generateMakefile(output, model_names, lstsmodelname, create_taskswitcher)
        print "done"
        print "Creating testdata...",
        self.__createDataTables(output)
        print "done"
        print "Creating coverage requirements based on the use cases...",
        self.__createCoverageRequirements(output, lstsmodelname)
        print "done"

    def __writeLsts(self,lsts_model, model_name, outputDir):

        transitions = []

        states = lsts_model.getStates()
        actions = lsts_model.getActions()
        state_props = {}
        refinements = []

        for state in lsts_model.getStates():
            state_transitions = []
            for transition in state.getTransitions():
                #print states[0] == transition.getFromState()
                state_transitions.append((states.index(transition.getToState()), actions.index(transition.getAction())+1))

            transitions.append(state_transitions)

            for state_prop in state.getState_propositions():
                if state_prop.getName() in state_props:
                    state_props[state_prop.getName()].append(states.index(state))

                else:
                    state_props[state_prop.getName()] = []
                    state_props[state_prop.getName()].append(states.index(state))
                    if state_prop.getKeywords() != None and len(state_prop.getKeywords()) > 0:
                        if state_prop.getName() != "svStart":
                            refinements.append((state_prop.getName(), state_prop.getKeywords()))

        action_names = []

        for action in actions:
            action_names.append(action.getName())
            if action.getRefinements() != None:
                refinements.append((action.getName(),action.getRefinements()))

        #self.__mergeStates(transitions, actions)

        action_machine_file = open(outputDir + model_name + ".lsts", "w")
        ref_machine_file = codecs.open(outputDir + "rm" + os.sep + model_name + "-rm.lsts", "w", "iso-8859-1")

        w = lsts.writer(action_machine_file)
        w.set_actionnames(action_names)
        w.set_transitions(transitions)

        w.set_stateprops(state_props)
        w.get_header().initial_states = states.index(lsts_model.getStart_state())

        w.write()

        #write refinement machines
        self.__writeRefinementMachine(refinements, ref_machine_file)

    def __mergeStates(self, transitionsList, actions):
        """
        Checks model for nondeterminism. If there is multiple transition with same action leaving a state,
        the target states of theses transitions are merged. This is currently needed to merge situations
        where multiple transitons are connected to a single InGate.

        NOTE: does not work in situations where there are transitions to the merging states outside from the state
        that is nondeterministic!

        TODO: Slow in big models ???

        removable_states = []

        for state_transitions in transitionsList:

            if state_transitions in removable_states: continue

            found = True

            while found:

                found = False

                for t1 in state_transitions:

                    if found: break

                    for t2 in state_transitions:

                        if t1 != t2 and t1[0] != t2[0] and t1[1] == t2[1]:
                            print "Indeterminism found! Merging states."
                            #state_transition.remove(t2)
                            mergingState = transitionsList[t2[0]]
                            mergeState = transitionsList[t1[0]]
                            mergeState.extend(mergingState)
                            removable_states.append(mergingState)
                            state_transitions.remove(t2)
                            found = True
                            break

        for rs in removable_states:
            #fix indexes of the transtitions
            removed_index = transitionsList.index(rs)

            transitionsList.remove(rs)

            for state_transitions in transitionsList:
                temp_transitions = []
                for t in state_transitions:
                    if t[0] > removed_index:
                        temp = (t[0] - 1, t[1])
                        state_transitions[state_transitions.index(t)] = temp

       """

    def __writeRefinementMachine(self, refinements, file):

        transitions = []
        actions = []

        #add central state
        transitions.append([])

        for ref in refinements:
            refName = ref[0]
            keywords = ref[1]

            #start aw/sv
            transitions.append([])
            actions.append("start_" + refName)
            transitions[0].append((len(transitions) - 1, len(actions)))

            prev_state_index = len(transitions) - 1

            #keywords
            for kw in keywords:

                if kw.strip() == "": continue

                matches = re.findall("\$(\w+)\$",kw)
                if matches != None and len(matches) > 0:
                    for match in matches:
                        #kw = lstsmodel.escape(kw.replace(match,"(OUT = " + match + ".name" + ")"))
                        kw = kw.replace(match,"(OUT = " + self.__removeIllegalChars(match).lower() + ")")
                if kw in actions:
                    kw_index = actions.index(kw) + 1
                else:
                    actions.append(kw)
                    kw_index = len(actions)

                transitions.append([])
                transitions[prev_state_index].append((len(transitions) - 1, kw_index))
                prev_state_index = len(transitions) - 1

            #end aw/sv
            actions.append("end_" + refName)
            transitions[prev_state_index].append((0, len(actions)))

        w = lsts.writer(file)
        w.set_actionnames(actions)
        w.set_transitions(transitions)

        w.write()

    def __createFlagModels(self, directory):

        for flag in self.__kendoXMLParser.getFlags():
            actions = []
            transitions = []

            #Enabled state
            transitions.append([])
            enabled_index = 0

            #Disabled state
            transitions.append([])
            disabled_index = 1

            enableAction = "ALLOW<Enabled" + flag.getName() + ">"
            disableAction = "ALLOW<Disabled" + flag.getName() + ">"

            toEnabledAction = "ALLOW<toEnabled" + flag.getName() + ">"
            toDisabledAction = "ALLOW<toDisabled" + flag.getName() + ">"

            actions.append(enableAction)
            enabled_action_index = 1

            actions.append(disableAction)
            disabled_action_index = 2

            actions.append(toDisabledAction)
            toDisabled_action_index = 3

            actions.append(toEnabledAction)
            toEnabled_action_index = 4

            transitions[enabled_index].append((disabled_index, toDisabled_action_index))
            transitions[enabled_index].append((enabled_index, enabled_action_index))
            transitions[enabled_index].append((enabled_index, toEnabled_action_index))

            transitions[disabled_index].append((disabled_index, toDisabled_action_index))
            transitions[disabled_index].append((disabled_index, disabled_action_index))
            transitions[disabled_index].append((enabled_index, toEnabled_action_index))

            file = open(directory + "flagmodel_" + flag.getName() + ".lsts", "w")

            w = lsts.writer(file)
            w.set_actionnames(actions)
            w.set_transitions(transitions)

            #Set right intial state based on the flag default state
            if flag.getDefault_value() == False:
                w.get_header().initial_states = disabled_index
            else:
                w.get_header().initial_states = enabled_index

            w.write()

            ref_machine_file = open(directory + "rm" + os.sep + "flagmodel_" + flag.getName() + "-rm.lsts", "w")

            #write refinement machines
            self.__writeRefinementMachine({}, ref_machine_file)

    def __createCoverageRequirements(self, directory, project_name):

        covRegNames = []
        covRegs = []

        ucModel = self.__kendoXMLParser.getUseCaseModel()

        file = open(directory + "usecase_coverage_requirements.txt", "w")

        if not ucModel:
            return

        for uc in ucModel.getUseCases():

            if uc.getDescription() != None and uc.getDescription() != "":
                description = ", description: " + uc.getDescription()
            else:
                description = ""

            file.write("Use case: " + uc.getName() + description + "\n\n")
            for path in uc.getPaths():
                actions = []

                for t in path.getTransitions():
                    modelName = t[0]
                    transitionId = t[1]

                    product = None
                    transitionName = None

                    for p in self.__kendoXMLParser.getProducts():
                        if p.getName() == modelName:
                            product = p
                            break

                    if product:
                        for tt in product.getTransitions():
                            if tt.getId() == transitionId:
                                transitionName = tt.getEvent_id()
                                break

                        if transitionName:

                            actions.append(lstsmodel.getModelName(product) +":end_aw"+ transitionName)

                file.write("Path: " + path.getName() + ", " + path.getDescription() +"\n")
                covRegNames.append(uc.getName() + " : " + path.getName())

                covreg = ""
                for a in actions:

                    if a == actions[0]:
                        covreg += "action " + a
                    else:
                        covreg += " THEN action " + a

                covRegs.append(covreg)
                file.write(covreg + "\n\n")

            file.write("\n\n")

        file.close()

        self.__createTestExecutionScript(covRegNames, covRegs, project_name, directory)

    def __createTestExecutionScript(self, covRegNames, covRegs, project_name, directory):

        """

        echo ""
        echo -n "Tallennetaanko loki ja makefile? [k/e] "
        read answer

        if [ "$answer" == "k" ]; then
            aikaleima=`date +"%F_%T" | sed 's/:/./g'`
            echo "Tallennan. Kirjoita kommentti"
                read kommentti
            cp -v /tmp/testengine-lastrun-demo.log logs/testrun-$aikaleima-$kommentti.log
            cp -v Makefile logs/testrun-$aikaleima.mak
            echo "Tallennettu."
        else
            echo "En tallentanut. Olisin tallentanut tiedostot:"
            echo "/tmp/testengine-lastrun.log"
            echo "Makefile"
        fi
        """

        file = open(directory + "run_test.sh", "w")

        script = "#!/bin/bash\n\n"

        script += """if [ "$1x" == "x" ]; then
            port=9095
        else
            port=$1
        fi
        """

        if covRegs and len(covRegs) > 0:
            i = 1
            for c in covRegs:
                script += "covRegs[" + str(i) + "]=\"" + c +"\"\n\n"
                i += 1

        script += "echo Choose coverage requirement:\n\n"

        i = 1
        if covRegs and len(covRegs) > 0:
            script += "echo Use cases:\n"

            for c in covRegNames:
                script += "echo \"" + str(i) + ": " + c +"\"\n"
                i += 1
            script += "echo \"\"\n"

        script += "echo " + str(i) + ": Define new coverage requirement\n"
        script += "echo -n \"> \"\n"
        script += "read choice\n"

        script += "if [ $choice == "+str(i) +" ]\n"
        script += "then\n"
        script += "echo \"Enter coverage requirement: \"\n"
        script += "echo -n \"> \"\n"
        script += "read covReg\n"
        script += "else\n"
        script += "covReg=${covRegs[$choice]}\n"
        script += "fi\n"

        script += "echo executing coverage requirement: $covReg\n"

        script += "echo \"Choose heuristics:\"\n"
        script += "echo 1 : Random\n"
        script += "echo 2 : Greedy\n"
        script += "echo -n \"> \"\n"
        script += "read guidance\n"

        script += "if [ $guidance == 1 ]\n"
        script += "then\n"
        script += "guidance=\"randomguidance\"\n"

        script += "args=\"randomseed:$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]$[$RANDOM%10]\"\n"
        script += "echo $args\n"
        script += "elif [ $guidance == 2 ]\n"
        script += "then\n"
        script += "guidance=\"greedyguidance\"\n"
        script += "args=\"max_states:10000\"\n"
        script += "fi\n"

        script  += """tema testengine \\
            --model=parallellstsmodel:""" + project_name + """-rules.parallel \\
            --coveragereq="$covReg" \\
            --guidance="$guidance" \\
            --guidance-args="$args" \\
            --adapter-args="port:$port" \\
            --actionpp='' \\
            --actionpp-args='' \\
            --testdata='file:testdata.td' \\
            --logger='fdlogger' \\
            --logger-args='targetfile:/tmp/testengine-lastrun-""" + project_name + """.log,targetfd:stdout'"""

        file.write(script)

    def __generateMakefile(self, directory, model_names, project_name, generate_ts):

        file = open(directory + "Makefile", "w")
        file.write("all: " +project_name+"-rules.parallel\n")
        file.write("\n")
        file.write(project_name+"-rules.parallel:\n")
        file.write("\tmake -f Makefile-" + project_name + "\n")
        file.write("\n")
        file.write("clean:\n")
        file.write("\tmake -f Makefile-"+project_name+" clean")
        file.close()

        makefile_name = "Makefile-" + project_name
        file = open(directory + makefile_name, "w")

        models = ""
        for name in model_names:
            models = models + " " + name

        file.write("ACTIONMACHINELIST =")# +models)
        for m in model_names[0:-1]:
            file.write(m + " \\\n")
        file.write(model_names[-1])

        file.write("\n\n")

        file.write("DEVICE = rm")
        file.write("\n\n")
        file.write("RESULT = " + project_name + "-rules.parallel")
        file.write("\n\n")
        file.write("PYTHONLIBS=$(TEMA_ENGINE_HOME)/tema")
        file.write("\n\n")
        if generate_ts: file.write("#")
        file.write("TASKSWITCHERGEN=TaskSwitcher-"+project_name)
        file.write("\n")
        if generate_ts: file.write("#")
        file.write("TASKSWITCHERGENRM=TaskSwitcher-"+project_name+"-rm")
        file.write("\n\n")
        file.write("include $(TEMA_MODEL_TOOLS)/GNUmakefile.include")

    def __createDataTables(self, directory):
        """
        NOTE: Uses only the first data item. Rest dataitems are omitted.
        """

        file = codecs.open(directory + "testdata.td", "w","iso-8859-1")
        for dataEntity in self.__kendoXMLParser.getTestData():
            name = dataEntity.getLogicalName()
            if name == None or name == "":
                continue
            name = self.__removeIllegalChars(name).lower()

            if len(dataEntity.getItems()) > 0:
                file.write(name[1:len(name) - 1] + ":[")

                for dataItem in dataEntity.getItems():

                    #Escape quotes
                    #TODO: re.escape ?
                    itemName = dataItem.getName()
                    itemName = re.sub("'","\\'",itemName)
                    itemName = re.sub("\"","\\\"",itemName)
                    #itemName = re.sub("\\","\\\\",itemName)

                    file.write("'" + itemName + "'")
                    if dataItem != dataEntity.getItems()[-1]:
                        file.write(",")

                file.write("]\n")

            """
            try:
                dataItem = dataEntity.getItems()[0]
            except:
                continue

            itemName = dataItem.getName()
            itemName = re.sub("'","\\'",itemName)
            itemName = re.sub("\"","\\\"",itemName)
            file.write(name[1:len(name) - 1] + ":['" + itemName + "']\n")
            """
        file.close()

        """
        file = .open(directory + "testdata.td", "w","utf-8")

        logNames = []
        values = []

        for dataEntity in self.__kendoXMLParser.getTestData():
            name = dataEntity.getLogicalName()
            if name == None or name == "":
                continue
            logName = lstsmodel.escape(name[1:len(name) - 1])
            try:
                dataItem = dataEntity.getItems()[0]
            except:
                continue
            logNames.append(logName)
            values.append(dataItem.getName())

        file.write("Testdata(")
        for n in logNames:
            file.write(n)
            if n != lognames[-1]:
                file.write(",")

        file.write("):[(")
        for n in logNames:
            file.write(n)
            if n != lognames[-1]:
                file.write(",")
        file.write(")]\n")

        file.close()

        """

    def __removeIllegalChars(self,line):

        line = re.sub("\s|\W","_",line)
        if re.match("\d",line[0]):
            line = "_" + line
        return line

if __name__ == "__main__":

    #Parse command line arguments
    parser = optparse.OptionParser(usage="usage: %prog [options] input_file", description=tool_description)
    parser.add_option("-o", "--output", dest="outdir",
                      help="Output path for the generated lsts model.")
    parser.add_option("--fullts", dest="full_ts", default=False, action="store_true",
                      help="Generate a task switcher model from the ATS4 AppModel system model including all states and transitions..")
    parser.add_option("-t","--taskswitcher", dest="simple_ts", default=False, action="store_true",
                      help="Generate simplified task switcher from the system model that includes activations between application models but omits all other states and transitions..")
    parser.add_option("--generateSleep", dest="generateSleep", default = False, action="store_true",
                      help="Generate sleepts/wakets transitions for tagged states")
    parser.add_option("--sleepByDefault", dest="defaultSleep", default = False, action="store_true",
                      help="Handle states with no CanSleep/CanNotSleep tag as CanSleeps")
    #parser.add_option("-s", dest="sys_model",
    #                  help="ATS4 AppModel system model xml-file that is converted")
    #parser.add_option(")
    outputdir = None

    #Argument parsing...
    (options, args) = parser.parse_args()

    if len(args) != 1:
        parser.error("incorrect number of arguments")
        exit(1)
    else:
        if(options.outdir):
            if os.path.exists(options.outdir):
                print "Directory \""+ options.outdir +"\" exists. Overwrite? (y/n): ",
                while True:
                    answer = raw_input("").strip().lower()
                    if answer == 'y' or answer == 'yes':
                        try:
                            shutil.rmtree(options.outdir)
                            break
                        except:
                            print "Directory could not be rewritten"
                            exit(1)
                    elif answer == 'n' or answer == 'no':
                        exit(0)
                    else:
                        print "Please answer 'y' or 'n'."

            outputdir = options.outdir
        else:
            print "Output directory must be defined."
            exit(1)

    if not os.path.exists(args[0]):
        print "Model: " + args[0] + " does not exist!"
        exit(1)

    sysmodefile = args[0]

    converter = Kendo2Lsts()
    #converter.parseKendoModel("voicerecorder_port.xml")
    print "Reading ATS4 AppModel model...",
    if not converter.readKendoModel(sysmodefile):
        exit(1)
    print "done"
    #converter.printKendoModel()
    converter.writeLstsModel(outputdir, options.full_ts or options.simple_ts, options.simple_ts,options.generateSleep, options.defaultSleep)
    print "Conversion complete."


text:
//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

namespace Microsoft.Azure.Management.DataLake.StoreUploader
{
    /// <summary>
    /// Represents a class used for reporting upload progress on a segment.
    /// </summary>
    public class SegmentUploadProgress
    {

        /// <summary>
        /// Creates a new segment progress report.
        /// </summary>
        /// <param name="segmentNumber">The segment number the report refers to.</param>
        /// <param name="segmentLength">The segment length, in bytes.</param>
        /// <param name="uploadedByteCount">The number of bytes uploaded so far.</param>
        /// <param name="isFailed">Whether the upload operation failed.</param>
        internal SegmentUploadProgress(int segmentNumber, long segmentLength, long uploadedByteCount, bool isFailed)
        {
            this.SegmentNumber = segmentNumber;
            this.Length = segmentLength;
            this.UploadedByteCount = uploadedByteCount;
            this.IsFailed = isFailed;
        }

        /// <summary>
        /// Gets a value indicating the segment number this progress report refers to.
        /// </summary>
        /// <value>
        /// The segment number.
        /// </value>
        public int SegmentNumber { get; private set; }

        /// <summary>
        /// Gets a value indicating the segment length, in bytes.
        /// </summary>
        /// <value>
        /// The length.
        /// </value>
        public long Length { get; private set; }

        /// <summary>
        /// Gets a value indicating whether the upload failed or not.
        /// </summary>
        /// <value>
        ///   <c>true</c> if this instance is failed; otherwise, <c>false</c>.
        /// </value>
        public bool IsFailed { get; internal set; }

        /// <summary>
        /// Gets a value indicating the number of bytes uploaded so far for this segment.
        /// </summary>
        /// <value>
        /// The uploaded byte count.
        /// </value>
        public long UploadedByteCount { get; internal set; }

    }
}

redpajama_set_name: RedPajamaGithub


text:
package uk.ac.open.kmi.iserve.sal.util.metrics;

/**
 * Dummy implementation. It does not register anything.
 *
 * @author Pablo Rodríguez Mier.
 */
public class DummyMetrics implements CounterMetrics {

    @Override
    public int counter(String name) {
        return 0;
    }

    @Override
    public int increment(String name) {
        return 0;
    }

    @Override
    public int incrementBy(String name, int count) {
        return 0;
    }

    @Override
    public void reset() {
        // Do nothing
    }

    @Override
    public String toString() {
        return "Metrics Disabled. Use Metrics.enable() to activate metrics";
    }
}


text:
FROM nginx:1.11
MAINTAINER Michael J. Stealey <michael.j.stealey@gmail.com>

COPY . /tmp
RUN cp /tmp/config-files/hs-nginx.conf /etc/nginx/conf.d/default.conf \
    && cp /tmp/.htpasswd /etc/nginx/.htpasswd \
    && cp /tmp/docker-entrypoint.sh /docker-entrypoint.sh

# cleanup - rm from tmp began failing on 4/9/17 for some reason
#RUN rm -rf /tmp/*

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["run"]


text:
#ifndef CQChartsGraphVizPlot_H
#define CQChartsGraphVizPlot_H

#include <CQChartsConnectionPlot.h>
#include <CQChartsValueInd.h>
#include <CQChartsPlotType.h>
#include <CQChartsPlotObj.h>
#include <CQChartsBoxObj.h>
#include <CQChartsData.h>

class QFile;

//---

/*!
 * \brief Dot plot type
 * \ingroup Charts
 */
class CQChartsGraphVizPlotType : public CQChartsConnectionPlotType {
 public:
  using ColumnType = CQBaseModelType;

 public:
  CQChartsGraphVizPlotType();

  QString name() const override { return "graphviz"; }
  QString desc() const override { return "GraphViz"; }

  void addParameters() override;

  bool hasAxes() const override { return false; }

  bool canProbe() const override { return false; }

  bool canEqualScale() const override { return true; }

  QString description() const override;

  //---

  Plot *create(View *view, const ModelP &model) const override;
};

//---

class CQChartsGraphVizPlot;
class CQChartsGraphVizNodeObj;
class CQChartsGraphVizEdgeObj;
class CQChartsGraphVizPlotEdge;

/*!
 * \brief Graphviz Plot Node
 * \ingroup Charts
 */
class CQChartsGraphVizPlotNode {
 public:
  using Obj         = CQChartsGraphVizNodeObj;
  using Edge        = CQChartsGraphVizPlotEdge;
  using Edges       = std::vector<Edge *>;
  using Node        = CQChartsGraphVizPlotNode;
  using OptReal     = CQChartsOptReal;
  using ModelIndex  = CQChartsModelIndex;
  using Color       = CQChartsColor;
  using Alpha       = CQChartsAlpha;
  using FillPattern = CQChartsFillPattern;
  using LineDash    = CQChartsLineDash;
  using Length      = CQChartsLength;
  using ModelInds   = std::vector<ModelIndex>;
  using BBox        = CQChartsGeom::BBox;
  using Point       = CQChartsGeom::Point;
  using ShapeType   = CQChartsBoxObj::ShapeType;
  using EdgeRect    = std::map<Edge *, BBox>;

  CQChartsGraphVizPlotNode(const QString &str);
 ~CQChartsGraphVizPlotNode();

  //! get/set object
  Obj *obj() const { return obj_; }
  void setObj(Obj *obj);

  //! get/set rect
  const BBox &rect() const;
  void setRect(const BBox &rect);

  //! get/set edge parent
  Node *parent() const { return parent_; }
  void setParent(Node *parent) { parent_ = parent; }

  //! set string (name ?)
  QString str() const { return str_; }

  //! get/set unique id
  int id() const { return id_; }
  void setId(int id) { id_ = id; }

  int dotId() const { return dotId_; }
  void setDotId(int i) { dotId_ = i; }

  //! get/set name
  const QString &name() const { return name_; }
  void setName(const QString &v) { name_ = v; }

  //! get/set label
  const QString &label() const { return label_; }
  void setLabel(const QString &v) { label_ = v; }

  //! get/set value
  bool hasValue() const { return value_.isSet(); }
  const OptReal value() const { return value_; }
  void setValue(const OptReal &r) { value_ = r; }

  //! get/set group
  int group() const { return group_; }
  void setGroup(int ig, int ng=0) { group_ = ig; ngroup_ = ng; }
  int ngroup() const { return ngroup_; }

  //! get/set graph
  int graphId() const { return graphId_; }
  void setGraphId(int i) { graphId_ = i; }

  //! get/set parent graph
  int parentGraphId() const { return parentGraphId_; }
  void setParentGraphId(int i) { parentGraphId_ = i; }

  //! get/set depth
  int depth() const { return depth_; }
  void setDepth(int i) { depth_ = i; }

  //! get/set visible
  bool isVisible() const { return visible_; }
  void setVisible(bool b) { visible_ = b; }

  //! get/set model index
  const ModelIndex &ind() const { return ind_; }
  void setInd(const ModelIndex &ind) { ind_ = ind; }

  //---

  //! get/set source edges
  const Edges &srcEdges() const { return srcEdges_; }
  void setSrcEdges(const Edges &edges) { srcEdges_ = edges; }

  //! get/set destination edges
  const Edges &destEdges() const { return destEdges_; }
  void setDestEdges(const Edges &edges) { destEdges_ = edges; }

  //! add source edge (dest -> src)
  void addSrcEdge(Edge *edge, bool primary=true);

  //! add destination edge (src -> dest)
  void addDestEdge(Edge *edge, bool primary=true);

  //! has destination edge
  bool hasDestNode(Node *node) const;

  //---

  Edge *findSrcEdge (Node *node) const;
  Edge *findDestEdge(Node *node) const;

  //---

  const ModelInds &modelInds() const { return modelInds_; }

  void addModelInd(const ModelIndex &i) { modelInds_.push_back(i); }

  //---

  //--- custom appearance

  //! get/set shape
  ShapeType shapeType() const { return static_cast<ShapeType>(shapeTypeData_.shapeType); }
  void setShapeType(const ShapeType &s) {
    shapeTypeData_.shapeType = static_cast<CQChartsShapeType>(s); }

  //! get/set number of sides
  int numSides() const { return shapeTypeData_.numSides; }
  void setNumSides(int n) { shapeTypeData_.numSides = n; }

  //! get/set fill color
  const Color &fillColor() const { return fillData_.color; }
  void setFillColor(const Color &c) { fillData_.color = c; }

  //! get/set fill alpha
  const Alpha &fillAlpha() const { return fillData_.alpha; }
  void setFillAlpha(const Alpha &c) { fillData_.alpha = c; }

  //! get/set fill pattern
  const FillPattern &fillPattern() const { return fillData_.pattern; }
  void setFillPattern(const FillPattern &c) { fillData_.pattern = c; }

  //! get/set stroke color
  const Color &strokeColor() const { return strokeData_.color; }
  void setStrokeColor(const Color &c) { strokeData_.color = c; }

  //! get/set stroke alpha
  const Alpha &strokeAlpha() const { return strokeData_.alpha; }
  void setStrokeAlpha(const Alpha &a) { strokeData_.alpha = a; }

  //! get/set stroke width
  const Length &strokeWidth() const { return strokeData_.width; }
  void setStrokeWidth(const Length &w) { strokeData_.width = w; }

  //! get/set stroke dash
  const LineDash &strokeDash() const { return strokeData_.dash; }
  void setStrokeDash(const LineDash &d) { strokeData_.dash = d; }

  //---

  void moveBy(const Point &delta);
  void scale(double fx, double fy);

  //---

  bool hasEdgePoint(Edge *edge) const;
  void setEdgePoint(Edge *edge, const Point &p);
  Point edgePoint(Edge *edge) const;

 private:
  struct FillData {
    Color       color;   //!< fill color
    Alpha       alpha;   //!< fill alpha
    FillPattern pattern; //!< fill pattern
  };

  struct StrokeData {
    Color    color; //!< stroke color
    Alpha    alpha; //!< stroke color alpha
    Length   width; //!< stroke width
    LineDash dash;  //!< stroke dash
  };

  using EdgePoints = std::map<int, Point>;

  Obj* obj_     { nullptr }; //!< node plot object
  bool visible_ { true };    //!< is visible

  Node*   parent_        { nullptr }; //!< parent node
  QString str_;                       //!< string
  int     id_            { -1 };      //!< id
  int     dotId_         { -1 };      //!< dot id
  QString name_;                      //!< name
  QString label_;                     //!< label
  OptReal value_;                     //!< value
  int     group_         { -1 };      //!< group
  int     ngroup_        { 0 };       //!< number of groups
  int     depth_         { -1 };      //!< depth
  int     graphId_       { -1 };      //!< graph id
  int     parentGraphId_ { -1 };      //!< parent graph id

  ModelIndex ind_; //!< model index

  BBox rect_; //!< placed rectangle

  // appearance
  CQChartsShapeTypeData shapeTypeData_; //!< shape type data

  FillData   fillData_;   //!< fill data
  StrokeData strokeData_; //!< stroke data

  // connections
  Edges     srcEdges_;         //!< source edges
  Edges     destEdges_;        //!< destination edges
  Edges     nonPrimaryEdges_;  //!< non-primary edges
  int       srcDepth_  { -1 }; //!< source depth (calculated)
  int       destDepth_ { -1 }; //!< destination depth (calculated)
  ModelInds modelInds_;        //!< model inds

  EdgePoints edgePoints_;
};

/*!
 * \brief Graphviz Plot Edge
 * \ingroup Charts
 */
class CQChartsGraphVizPlotEdge {
 public:
  enum class ShapeType {
    NONE,
    ARROW
  };

  using Obj        = CQChartsGraphVizEdgeObj;
  using Node       = CQChartsGraphVizPlotNode;
  using Column     = CQChartsColumn;
  using ModelIndex = CQChartsModelIndex;
  using ModelInds  = std::vector<ModelIndex>;
  using Color      = CQChartsColor;
  using OptReal    = CQChartsOptReal;
//using Line       = CQChartsGeom::Line;

 public:
  CQChartsGraphVizPlotEdge(const OptReal &value, Node *srcNode, Node *destNode);

  virtual ~CQChartsGraphVizPlotEdge();

  //---

  //! get/set object
  Obj *obj() const { return obj_; }
  void setObj(Obj *obj);

  //---

  //! get/set unique id
  int id() const { return id_; }
  void setId(int id) { id_ = id; }

  //! get/set value
  bool hasValue() const { return value_.isSet(); }
  const OptReal &value() const { return value_; }
  void setValue(const OptReal &r) { value_ = r; }

  //---

  //! get/set named column
  bool hasNamedColumn(const QString &name) const {
    return (namedColumn_.find(name) != namedColumn_.end());
  }

  Column namedColumn(const QString &name) const {
    auto p = namedColumn_.find(name);
    return (p != namedColumn_.end() ? (*p).second : Column());
  }

  void setNamedColumn(const QString &name, const Column &c) { namedColumn_[name] = c; }

  //---

  //! get/set label
  const QString &label() const { return label_; }
  void setLabel(const QString &s) { label_ = s; }

  //---

  // -- custom appearance --

  //! get/set shape
  const ShapeType &shapeType() const { return shapeType_; }
  void setShapeType(const ShapeType &s) { shapeType_ = s; }

  //! get/set fill color
  const Color &fillColor() const { return color_; }
  void setFillColor(const Color &c) { color_ = c; }

  //---

  const QModelIndex &modelInd() const { return modelInd_; }
  void setModelInd(const QModelIndex &v) { modelInd_ = v; }

  const ModelInds &modelInds() const { return modelInds_; }
  void addModelInd(const ModelIndex &i) { modelInds_.push_back(i); }

  //---

  // get source node
  Node *srcNode() const { return srcNode_; }

  // get destination node
  Node *destNode() const { return destNode_; }

  // is self connect
  bool isSelf() const { return srcNode() == destNode(); }

  //---

  //! get draw path
  const QPainterPath &path() const { return path_; }

  //! get/set edge path
  const QPainterPath &edgePath() const { return edgePath_; }
  void setEdgePath(const QPainterPath &path) { edgePath_ = path; }

#if 0
  //! get/set edge line
  const Line &line() const { return line_; }
  void setLine(const Line &line) { line_ = line; }
#endif

  //! get/set is directed
  bool isDirected() const { return directed_; }
  void setDirected(bool b) { directed_ = b; }

 private:
  using NamedColumn = std::map<QString, Column>;

  Obj*         obj_       { nullptr };         //!< edge plot object
  int          id_        { -1 };              //!< unique id
  OptReal      value_;                         //!< value
  NamedColumn  namedColumn_;                   //!< named columns
  QString      label_;                         //!< label
  ShapeType    shapeType_ { ShapeType::NONE }; //!< shape type
  Color        color_;                         //!< color
  QModelIndex  modelInd_;                      //!< original row model index
  ModelInds    modelInds_;                     //!< model inds
  Node*        srcNode_   { nullptr };         //!< source node
  Node*        destNode_  { nullptr };         //!< destination node
  QPainterPath path_;                          //!< draw path
  QPainterPath edgePath_;                      //!< edge path
//Line         line_;                          //!< edge line
  bool         directed_  { false };           //!< is directed
};

//---

class CQChartsGraphVizPlot;

/*!
 * \brief Graphviz Plot Node object
 * \ingroup Charts
 */
class CQChartsGraphVizNodeObj : public CQChartsPlotObj {
  Q_OBJECT

  Q_PROPERTY(QString       hierName  READ hierName  WRITE setHierName )
  Q_PROPERTY(QString       name      READ name      WRITE setName     )
  Q_PROPERTY(double        value     READ value     WRITE setValue    )
  Q_PROPERTY(int           depth     READ depth     WRITE setDepth    )
  Q_PROPERTY(ShapeType     shapeType READ shapeType WRITE setShapeType)
  Q_PROPERTY(int           numSides  READ numSides  WRITE setNumSides )
  Q_PROPERTY(CQChartsColor color     READ fillColor WRITE setFillColor)

  Q_ENUMS(ShapeType)

 public:
  enum class ShapeType {
    NONE          = static_cast<int>(CQChartsShapeType::NONE),
    TRIANGLE      = static_cast<int>(CQChartsShapeType::TRIANGLE),
    DIAMOND       = static_cast<int>(CQChartsShapeType::DIAMOND),
    BOX           = static_cast<int>(CQChartsShapeType::BOX),
    POLYGON       = static_cast<int>(CQChartsShapeType::POLYGON),
    CIRCLE        = static_cast<int>(CQChartsShapeType::CIRCLE),
    DOUBLE_CIRCLE = static_cast<int>(CQChartsShapeType::DOUBLE_CIRCLE),
    RECORD        = static_cast<int>(CQChartsShapeType::RECORD),
    PLAIN_TEXT    = static_cast<int>(CQChartsShapeType::PLAIN_TEXT)
  };

  using GraphVizPlot = CQChartsGraphVizPlot;
  using Node         = CQChartsGraphVizPlotNode;
  using Edge         = CQChartsGraphVizPlotEdge;
  using Color        = CQChartsColor;
  using Angle        = CQChartsAngle;

 public:
  CQChartsGraphVizNodeObj(const GraphVizPlot *plot, const BBox &rect, Node *node,
                          const ColorInd &ind);

  virtual ~CQChartsGraphVizNodeObj();

  //---

  //! get plot
  const GraphVizPlot *graphVizPlot() const { return graphVizPlot_; }

  //! get node
  Node *node() const { return node_; }

  //---

  //! get/set hier name
  const QString &hierName() const { return hierName_; }
  void setHierName(const QString &s) { hierName_ = s; }

  //! get/set name
  QString name() const;
  void setName(const QString &s);

  //! get/set value
  double value() const;
  void setValue(double r);

  //! get/set depth
  int depth() const;
  void setDepth(int depth);

  //---

  //! get/set shape type
  ShapeType shapeType() const;
  void setShapeType(const ShapeType &s);

  //! get/set num side
  int numSides() const;
  void setNumSides(int n);

  //! get/set color
  Color fillColor() const;
  void setFillColor(const Color &c);

  //---

  //! typename
  QString typeName() const override { return "node"; }

  //! get unique id
  QString calcId() const override;

  // get tip string
  QString calcTipId() const override;

  //---

  void addProperties(CQPropertyViewModel *model, const QString &path) override;

  //---

  //! move node by delta
  void moveBy(const Point &delta);

  //! scale node by factor
  void scale(double fx, double fy);

  //---

  void placeEdges();

  //---

  // Implement edit interface
  bool editPress  (const Point &p) override;
  bool editMove   (const Point &p) override;
  bool editMotion (const Point &p) override;
  bool editRelease(const Point &p) override;

  void setEditBBox(const BBox &bbox, const ResizeSide &) override;

  //---

  //! get select indices
  void getObjSelectIndices(Indices &inds) const override;

  //! get connected objects
  PlotObjs getConnected() const override;

  //---

  void draw(PaintDevice *device) const override;

  void drawFg(PaintDevice *device) const override;

  //---

  void calcPenBrush(PenBrush &penBrush, bool updateState) const override;

  QColor calcFillColor() const;

 protected:
  const GraphVizPlot* graphVizPlot_ { nullptr }; //!< parent plot
  Node*               node_         { nullptr }; //!< node
  QString             hierName_;                 //!< node hier name
  bool                editChanged_  { false };   //!< edit is changed
};

//---

/*!
 * \brief Graphviz Plot Edge object
 * \ingroup Charts
 */
class CQChartsGraphVizEdgeObj : public CQChartsPlotObj {
  Q_OBJECT

  Q_PROPERTY(ShapeType shapeType READ shapeType WRITE setShapeType)
  Q_PROPERTY(double    value     READ value)

  Q_ENUMS(ShapeType)

 public:
  enum class ShapeType {
    NONE,
    ARROW
  };

  using GraphVizPlot = CQChartsGraphVizPlot;
  using Edge         = CQChartsGraphVizPlotEdge;
  using Node         = CQChartsGraphVizPlotNode;
  using Length       = CQChartsLength;
  using Angle        = CQChartsAngle;

 public:
  CQChartsGraphVizEdgeObj(const GraphVizPlot *plot, const BBox &rect, Edge *edge);

  virtual ~CQChartsGraphVizEdgeObj();

  //---

  //! get plot
  const GraphVizPlot *graphVizPlot() const { return graphVizPlot_; }

  //! get/set edge
  Edge *edge() const { return edge_; }
  void setEdge(Edge *edge) { edge_ = edge; }

  //---

  //! typename
  QString typeName() const override { return "edge"; }

  //! get unique id
  QString calcId() const override;

  //! get tip string
  QString calcTipId() const override;

  //! get source/destination rect
  void setSrcRect (const BBox &rect) { srcRect_  = rect; }
  void setDestRect(const BBox &rect) { destRect_ = rect; }

  //! get/set shape type
  ShapeType shapeType() const;
  void setShapeType(const ShapeType &s);

  double value() const { return (edge()->hasValue() ? edge()->value().real() : 0.0); }

  //---

  void addProperties(CQPropertyViewModel *model, const QString &path) override;

  //---

  //! is point inside
  bool inside(const Point &p) const override;

  //---

  //! get select indices
  void getObjSelectIndices(Indices &inds) const override;

  //! get connected objects
  PlotObjs getConnected() const override;

  //---

  void draw(PaintDevice *device) const override;

  void drawFg(PaintDevice *device) const override;

  //---

  void calcPenBrush(PenBrush &penBrush, bool updateState) const override;

 protected:
  const GraphVizPlot*  graphVizPlot_ { nullptr }; //!< parent plot
  Edge*                edge_         { nullptr }; //!< edge
  BBox                 srcRect_;                  //!< src rect
  BBox                 destRect_;                 //!< dest rect
  mutable QPainterPath epath_;                    //!< line path
  mutable QPainterPath path_;                     //!< painter path
};

//---

/*!
 * \brief Graph Plot
 * \ingroup Charts
 */
class CQChartsGraphVizPlot : public CQChartsConnectionPlot,
 public CQChartsObjNodeShapeData<CQChartsGraphVizPlot>,
 public CQChartsObjNodeTextData <CQChartsGraphVizPlot>,
 public CQChartsObjEdgeShapeData<CQChartsGraphVizPlot>,
 public CQChartsObjEdgeTextData <CQChartsGraphVizPlot> {
  Q_OBJECT

  // plot type
  Q_PROPERTY(PlotType     plotType     READ plotType     WRITE setPlotType)
  Q_PROPERTY(OutputFormat outputFormat READ outputFormat WRITE setOutputFormat)

  // node data
  Q_PROPERTY(NodeShape      nodeShape  READ nodeShape    WRITE setNodeShape )
  Q_PROPERTY(bool           nodeScaled READ isNodeScaled WRITE setNodeScaled)
  Q_PROPERTY(CQChartsLength nodeSize   READ nodeSize     WRITE setNodeSize  )

  Q_PROPERTY(bool nodeTextSingleScale READ isNodeTextSingleScale WRITE setNodeTextSingleScale)

  // edge data
  Q_PROPERTY(EdgeShape      edgeShape    READ edgeShape      WRITE setEdgeShape   )
  Q_PROPERTY(bool           edgeArrow    READ isEdgeArrow    WRITE setEdgeArrow   )
  Q_PROPERTY(bool           edgeScaled   READ isEdgeScaled   WRITE setEdgeScaled  )
  Q_PROPERTY(CQChartsLength edgeWidth    READ edgeWidth      WRITE setEdgeWidth   )
  Q_PROPERTY(bool           edgeCentered READ isEdgeCentered WRITE setEdgeCentered)
  Q_PROPERTY(bool           edgePath     READ isEdgePath     WRITE setEdgePath    )
  Q_PROPERTY(double         arrowWidth   READ arrowWidth     WRITE setArrowWidth  )
  Q_PROPERTY(bool           edgeWeighted READ isEdgeWeighted WRITE setEdgeWeighted)

  // options
  Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)

  // coloring
  Q_PROPERTY(bool blendEdgeColor READ isBlendEdgeColor WRITE setBlendEdgeColor)

  // placement data
  //  . fdp
  Q_PROPERTY(double fdpK       READ fdpK       WRITE setFdpK      )
  Q_PROPERTY(int    fdpMaxIter READ fdpMaxIter WRITE setFdpMaxIter)
  Q_PROPERTY(int    fdpStart   READ fdpStart   WRITE setFdpStart  )
  Q_PROPERTY(double fdpEdgeLen READ fdpEdgeLen WRITE setFdpEdgeLen)

  Q_PROPERTY(int processTimeout READ processTimeout WRITE setProcessTimeout)

  // node/edge shape/text data
  CQCHARTS_NAMED_SHAPE_DATA_PROPERTIES(Node, node)
  CQCHARTS_NAMED_TEXT_DATA_PROPERTIES (Node, node)

  CQCHARTS_NAMED_SHAPE_DATA_PROPERTIES(Edge, edge)
  CQCHARTS_NAMED_TEXT_DATA_PROPERTIES (Edge, edge)

  Q_ENUMS(PlotType)
  Q_ENUMS(OutputFormat)

  Q_ENUMS(NodeShape)
  Q_ENUMS(EdgeShape)

 public:
  enum class NodeShape {
    NONE,
    DIAMOND,
    BOX,
    POLYGON,
    CIRCLE,
    DOUBLE_CIRCLE
  };

  enum class EdgeShape {
    NONE        = int(CQChartsEdgeType::NONE),
    LINE        = int(CQChartsEdgeType::LINE),
    RECTILINEAR = int(CQChartsEdgeType::RECTILINEAR),
    ARC         = int(CQChartsEdgeType::ARC)
  };

  enum class PlotType {
    DOT,
    NEATO,
    TWOPI,
    CIRCO,
    FDP,
    OSAGE,
    PATCHWORK,
    SFDP
  };

  enum class OutputFormat {
    JSON,
    XDOT,
    DOT
  };

  using Node        = CQChartsGraphVizPlotNode;
  using Nodes       = std::vector<Node *>;
  using NodeSet     = std::set<Node *>;
  using Edge        = CQChartsGraphVizPlotEdge;
  using Edges       = std::vector<Edge *>;
  using NodeObj     = CQChartsGraphVizNodeObj;
  using EdgeObj     = CQChartsGraphVizEdgeObj;
  using Length      = CQChartsLength;
  using Color       = CQChartsColor;
  using Alpha       = CQChartsAlpha;
  using PenData     = CQChartsPenData;
  using PenBrush    = CQChartsPenBrush;
  using TextOptions = CQChartsTextOptions;
  using ColorInd    = CQChartsUtil::ColorInd;

 public:
  CQChartsGraphVizPlot(View *view, const ModelP &model);
 ~CQChartsGraphVizPlot();

  //---

  void init() override;
  void term() override;

  //---

  //! get/set node shape
  NodeShape nodeShape() const { return nodeShape_; }
  void setNodeShape(const NodeShape &s);

  //! get/set is node scaled
  bool isNodeScaled() const { return nodeScaled_; }
  void setNodeScaled(bool b);

  //! get/set node size
  const Length &nodeSize() const { return nodeSize_; }
  void setNodeSize(const Length &s);

  //! get/set node text single scale
  bool isNodeTextSingleScale() const { return nodeTextSingleScale_; }
  void setNodeTextSingleScale(bool b);

  //---

  //! get/set edge shape
  const EdgeShape &edgeShape() const { return edgeShape_; }
  void setEdgeShape(const EdgeShape &s);

  //! get/set has arrow
  bool isEdgeArrow() const { return edgeArrow_; }
  void setEdgeArrow(bool b);

  //! get/set is edge scaled
  bool isEdgeScaled() const { return edgeScaled_; }
  void setEdgeScaled(bool b);

  //! get/set edge width
  const Length &edgeWidth() const { return edgeWidth_; }
  void setEdgeWidth(const Length &l);

  //! get/set is edge centered
  bool isEdgeCentered() const { return edgeCentered_; }
  void setEdgeCentered(bool b);

  //! get/set use edge path
  bool isEdgePath() const { return edgePath_; }
  void setEdgePath(bool b);

  //! get/set edge directed arrow width
  double arrowWidth() const { return arrowWidth_; }
  void setArrowWidth(double r);

  //! get/set edge weighted
  bool isEdgeWeighted() const { return edgeWeighted_; }
  void setEdgeWeighted(bool b);

  //---

  //! get/set orientation
  const Qt::Orientation &orientation() const;
  void setOrientation(const Qt::Orientation &o);

  bool isHorizontal() const { return orientation() == Qt::Horizontal; }
  bool isVertical  () const { return orientation() == Qt::Vertical  ; }

  //---

  //! get/set blend node colors for edge
  bool isBlendEdgeColor() const { return blendEdgeColor_; }
  void setBlendEdgeColor(bool b);

  //---

  double fdpK() const { return fdpK_; }
  void setFdpK(double r);

  int fdpMaxIter() const { return fdpMaxIter_; }
  void setFdpMaxIter(int i);

  int fdpStart() const { return fdpStart_; }
  void setFdpStart(int i);

  double fdpEdgeLen() const { return fdpEdgeLen_; }
  void setFdpEdgeLen(double r);

  int processTimeout() const { return processTimeout_; }
  void setProcessTimeout(int i) { processTimeout_ = i; }

  //---

  const PlotType &plotType() const { return plotType_; }
  void setPlotType(const PlotType &t);

  const OutputFormat &outputFormat() const { return outputFormat_; }
  void setOutputFormat(const OutputFormat &f);

  //---

  // add properties
  void addProperties() override;

  //---

  Range calcRange() const override;

//Range getCalcDataRange() const override;

  Range objTreeRange() const override;

  BBox nodesBBox() const;

  //---

  const Nodes &nodes() const { return nodes_; }

  int numNodes() const { return int(nodes_.size()); }

  const Edges &edges() const { return edges_; }

  //---

  bool createObjs(PlotObjs &objs) const override;

  //---

  bool writeGraph(bool weighted=true) const;
  bool writeGraph(QFile &graphVizFile, const QString &graphVizFilename, bool weighted) const;
  bool processGraph(const QString &graphVizFilename, QFile &outFile,
                    const QString &outFilename, const QString &typeName) const;

  //---

  void fitToBBox(const BBox &bbox);

  //---

  bool initHierObjs() const;

  void initHierObjsAddHierConnection(const HierConnectionData &srcHierData,
                                     const HierConnectionData &destHierData) const override;
  void initHierObjsAddLeafConnection(const HierConnectionData &srcHierData,
                                     const HierConnectionData &destHierData) const override;

  void initHierObjsAddConnection(const QString &srcStr, const QString &destStr, int srcDepth,
                                 double value, Node* &srcNode, Node* &destNode) const;

  void updateSrcDestNames(Node *srcNode, const HierConnectionData &srcHierData,
                          Node *destNode, const HierConnectionData &destHierData) const;

  //---

  bool initPathObjs() const;

  void addPathValue(const PathData &pathData) const override;

  void propagatePathValues();

  //---

  bool initFromToObjs() const;

  void addFromToValue(const FromToData &fromToData) const override;

  //---

  bool initLinkObjs() const;

  void addLinkConnection(const LinkConnectionData &linkConnectionData) const override;

  //---

  bool initConnectionObjs() const;

  void addConnectionObj(int id, const ConnectionsData &connectionsData,
                        const NodeIndex &nodeIndex) const override;

  //---

  bool initTableObjs() const;

  //---

  void processNodeNameValues(Node *node, const NameValues &valueValues) const;
  void processNodeNameValue (Node *node, const QString &name, const QString &value) const;

  void processEdgeNameValues(Edge *edge, const NameValues &valueValues) const;

  //---

  static void stringToShapeType(const QString &str, Node::ShapeType &shapeType);
  static QString shapeTypeToString(const Node::ShapeType &shapeType);

  static void stringToShapeType(const QString &str, Edge::ShapeType &shapeType);
  static QString shapeTypeToString(const Edge::ShapeType &shapeType);

  //---

  void filterObjs();

  //---

  void preDrawFgObjs (PaintDevice *) const override;
  void postDrawFgObjs(PaintDevice *) const override;

  //---

  struct DrawTextData {
    Point       p;
    BBox        rect;
    QString     str;
    QColor      c;
    TextOptions textOptions;
    bool        isRect { false };

    DrawTextData(const Point &p, const QString &str, const QColor &c,
                 const TextOptions &textOptions) :
     p(p), str(str), c(c), textOptions(textOptions) {
    }

    DrawTextData(const BBox &rect, const QString &str, const QColor &c,
                 const TextOptions &textOptions) :
     rect(rect), str(str), c(c), textOptions(textOptions), isRect(true) {
    }
  };

  using DrawTextDatas = std::vector<DrawTextData>;

  void addDrawTextData(const DrawTextData &data) { drawTextDatas_.push_back(data); }

  //---

  int maxNodeDepth() const { return maxNodeDepth_; }

  //---

  bool keyPress(int key, int modifier) override;

  //---

  void addObjects(PlotObjs &objs) const;

  //---

  bool hasForeground() const override;

  void execDrawForeground(PaintDevice *) const override;

  //---

  const OptReal &maxNodeValue() const { return maxNodeValue_; }
  const OptReal &maxEdgeValue() const { return maxEdgeValue_; }

 protected:
  void clearNodesAndEdges();

  Node *findNode(const QString &name, bool create=true) const;

  Node *findIdNode(int dotId) const;

  //---

  bool addMenuItems(QMenu *menu, const Point &p) override;

  //---

  Node *createNode(const QString &name) const;
  Edge *createEdge(const OptReal &value, Node *srcNode, Node *destNode) const;

  NodeObj *createObjFromNode(Node *node) const;

  EdgeObj *addEdgeObj(Edge *edge) const;

  //---

  const BBox &bbox() const { return bbox_; }

  //---

  virtual NodeObj *createNodeObj(const BBox &rect, Node *node, const ColorInd &ind) const;
  virtual EdgeObj *createEdgeObj(const BBox &rect, Edge *edge) const;

  //---

  void printStats();

 protected:
  CQChartsPlotCustomControls *createCustomControls() override;

 protected:
  friend class CQChartsGraphVizPlotNode;

 private:
  using NameNodeMap = std::map<QString, Node *>;
  using IndNodeMap  = std::map<int, Node *>;
  using NameNameMap = std::map<QString, QString>;

  // node data
  NodeShape nodeShape_  { NodeShape::NONE };    //!< node shape
  bool      nodeScaled_ { false };              //!< is node scaled
  Length    nodeSize_   { Length::pixel(128) }; //!< node size

  bool nodeTextSingleScale_ { true }; //!< node text single scale factor

  // edge data
  EdgeShape edgeShape_    { EdgeShape::ARC };   //!< edge shape
  bool      edgeArrow_    { false };            //!< edge arrow
  bool      edgeScaled_   { false };            //!< scale width by value
  Length    edgeWidth_    { Length::pixel(8) }; //!< max edge width
  bool      edgeCentered_ { false };            //!< is edge centered
  bool      edgePath_     { false };            //!< use edge path
  double    arrowWidth_   { 1.0 };              //!< edge arrow size factor

  // plot data
  Qt::Orientation orientation_  { Qt::Vertical };       //!< orientation
  PlotType        plotType_     { PlotType::FDP };      //!< plot type
  OutputFormat    outputFormat_ { OutputFormat::XDOT }; //!< output format

  // bbox, margin, node width
  BBox   targetBBox_ { -1, -1, 1, 1 }; //!< target range bbox

  // coloring
  bool blendEdgeColor_ { false }; //!< blend edge color

  // placement data
  double fdpK_       { -1.0 };
  int    fdpMaxIter_ { -1 };
  int    fdpStart_   { -1 };
  double fdpEdgeLen_ { -1.0 };

  int processTimeout_ { 60 }; //!< graphviz process timeout

  // data
  Nodes            nodes_;                  //!< all nodes
  NameNodeMap      nameNodeMap_;            //!< name node map
  IndNodeMap       indNodeMap_;             //!< ind node map
  NameNameMap      nameNameMap_;            //!< name node map
  Edges            edges_;                  //!< all edges
  BBox             bbox_;                   //!< bbox
  CQChartsValueInd groupValueInd_;          //!< group value ind
  int              maxNodeDepth_  { 0 };    //!< max node depth (all graphs)
  double           edgeMargin_    { 0.01 }; //!< edge bounding box margin
  int              numGroups_     { 1 };    //!< node number of groups
  bool             edgeWeighted_  { true }; //!< edge placement weighted by value

  OptReal maxNodeValue_;
  OptReal maxEdgeValue_;

  DrawTextDatas drawTextDatas_;
};

//---

/*!
 * \brief Graphviz Plot plot custom controls
 * \ingroup Charts
 */
class CQChartsGraphVizPlotCustomControls : public CQChartsConnectionPlotCustomControls {
  Q_OBJECT

 public:
  using Color = CQChartsColor;

 public:
  CQChartsGraphVizPlotCustomControls(CQCharts *charts);

  void init() override;

  void addWidgets() override;

  void setPlot(Plot *plot) override;

 public Q_SLOTS:
  void updateWidgets() override;

 protected:
  void connectSlots(bool b) override;

  //---

  Color getColorValue() override;
  void setColorValue(const Color &c) override;

 protected:
  CQChartsGraphVizPlot* graphVizPlot_ { nullptr };
};

#endif


text:
static char PACKET_PATH[MAX_PATH] = {0};

static int AddSubdir_my(HANDLE hMpq, const char* root, const char* dir);

void PrintMessage(const char* fmt, ...) {

#ifdef _DEBUG
    va_list args;
    char msg[4096] = {0};
    va_start(args, fmt);
    vsnprintf(msg, sizeof(msg), fmt, args);
    va_end(args);
    printf("%s\n", msg);
#endif

}

static bool
IsDir(const char* name) {
	DIR *pDir = NULL;
	pDir = opendir(name);
	return pDir != NULL;
}

static bool
IsFullPath_my(const char* szFileName) {
#ifdef PLATFORM_WINDOWS
	if (('A' <= szFileName[0] && szFileName[0] <= 'Z') || ('a' <= szFileName[0] && szFileName[0] <= 'z')) {
		return (szFileName[1] == ":" && szFileName[2] == PATH_SEPARATOR);
	}
#endif
	// szFileName = szFileName;
	return false;
}

static size_t
FileStream_PrefixA_my(const char* szFileName, DWORD * pdwProvider) {
	TCHAR szFileNameT[MAX_PATH] = {0};
	size_t nPrefixLength = 0;
	if (szFileName != NULL) {
		CopyFileName(szFileNameT, szFileName, strlen(szFileName));
		nPrefixLength = FileStream_Prefix(szFileNameT, pdwProvider);
	}

	return nPrefixLength;
}

static void
CreateFullPathName_my(char* pBuffer, const char* pSubDir, const char* pNamePart1, const char* pNamePart2 = NULL) {
	size_t nPrefixLength = 0;
	size_t nLength;
	DWORD dwProvider = 0;
	bool bIsFullPath = false;
	char chSeparator = PATH_SEPARATOR;

	if (pNamePart1 != NULL) {
		nPrefixLength = FileStream_PrefixA_my(pNamePart1, &dwProvider);
		if ((dwProvider & BASE_PROVIDER_MASK) == BASE_PROVIDER_HTTP) {
			bIsFullPath = true;
			chSeparator = PATH_SEPARATOR;
		} else {
			bIsFullPath = IsFullPath_my(pNamePart1 + nPrefixLength);
		}
	}

	if (nPrefixLength > 0) {
		memcpy(pBuffer, pNamePart1, nPrefixLength);
		pNamePart1 += nPrefixLength;
		pBuffer += nPrefixLength;
	}

	if (bIsFullPath == false) {
		memcpy(pBuffer, PACKET_PATH, strlen(PACKET_PATH));
		pBuffer += strlen(PACKET_PATH);

		if (pSubDir != NULL && (nLength = strlen(pSubDir)) != 0) {
			assert(pSubDir[0] != PATH_SEPARATOR);
			assert(pSubDir[nLength - 1] != PATH_SEPARATOR);

			*pBuffer++ = PATH_SEPARATOR;

			memcpy(pBuffer, pSubDir, nLength);
			pBuffer += nLength;
		}
	}

	if (pNamePart1 != NULL && (nLength = strlen(pNamePart1)) != 0) {
		assert(pNamePart1[0] != PATH_SEPARATOR);
		assert(pNamePart1[nLength - 1] != PATH_SEPARATOR);

		if (bIsFullPath == false) {
			*pBuffer++ = PATH_SEPARATOR;
		}

		memcpy(pBuffer, pNamePart1, nLength);
		pBuffer += nLength;
	}

	if (pNamePart2 && (nLength = strlen(pNamePart2)) != 0) {
		memcpy(pBuffer, pNamePart2, nLength);
		pBuffer += nLength;
	}

	*pBuffer = 0;
}

static bool
CheckIfFileIsPresent_my(HANDLE hMpq, const char* pFileName, bool bShouldExist) {
	HANDLE hFile = NULL;
	if (SFileOpenFileEx(hMpq, pFileName, 0, &hFile)) {
		if (bShouldExist == false) {
			PRINT_MESSAGE("The file : %s is present, but it should not be", pFileName);
		}
		SFileCloseFile(hFile);
		return true;
	} else {
		if (bShouldExist) {
			PRINT_MESSAGE("the file %s is not present, but it should be", pFileName);
		}
		return false;
	}
}

void InitMyMpqScriptData(const char* path) {
	assert(strlen(path) <= MAX_PATH);
	memcpy(PACKET_PATH, path, strlen(path));
}

int
AddSubFile_my(HANDLE hMpq, const char* pDir, const char* pFileName) {
	int nError = ERROR_SUCCESS;

	DWORD dwCompression = MPQ_COMPRESSION_ZLIB;
	DWORD dwFlags = MPQ_FILE_ENCRYPTED | MPQ_FILE_COMPRESS;

    char chFileName[MAX_PATH] = {0};
    sprintf(chFileName, "%s/%s", pDir, pFileName);

    FILE *pFile = fopen(chFileName, "rb");
    assert(pFile);
    if (!pFile) {
    	nError = ERROR_FILE_NOT_FOUND;
    	return nError;
    }

    fseek(pFile, 0L, SEEK_END);
    size_t sz = ftell(pFile);
    fseek(pFile, 0L, SEEK_SET);

	HANDLE hFile = NULL;
	PRINT_MESSAGE("Adding file %s ...", pFileName);

	if (!SFileCreateFile(hMpq, pFileName, 0, sz, 0, dwFlags, &hFile)) {
		return GetLastError();
	}

    void * pBuffer = ::malloc(sz);
    int nLength = fread(pBuffer, 1, sz, pFile);
    assert(nLength != -1);
    if (nLength < sz || !SFileWriteFile(hFile, pBuffer, sz, dwCompression)) {
        PRINT_MESSAGE("Failed to write data to MQP");
        nError = GetLastError();
    }

    SFileCloseFile(hFile);
    fclose(pFile);
    ::free(pBuffer);
	return nError;
}

static int
IteratorDirection(HANDLE hMpq, const char* pRoot, const char* pSubDir) {
    int nError = ERROR_SUCCESS;

    char chFilePath[MAX_PATH] = {0};
    if (pSubDir) {
        sprintf(chFilePath, "%s/%s", pRoot, pSubDir);
    } else {
        sprintf(chFilePath, "%s", pRoot);
    }

    DIR *pstDir = opendir(chFilePath);
    struct dirent *pstEnt = NULL;
    while ((pstEnt = readdir(pstDir)) != NULL) {
        if (pstEnt->d_name[0] == '.')
            continue;

        if (pstEnt->d_type & DT_DIR) {
            if (strcmp(pstEnt->d_name, ".") == 0 || strcmp(pstEnt->d_name, "..") == 0)
                continue;
            memset(chFilePath, 0, MAX_PATH);
            if (pSubDir) {
                sprintf(chFilePath, "%s/%s", pSubDir, pstEnt->d_name);
            } else {
                sprintf(chFilePath, "%s", pstEnt->d_name);
            }

            nError = IteratorDirection(hMpq, pRoot, chFilePath);
            assert(nError == ERROR_SUCCESS);
            if (nError != ERROR_SUCCESS)
                break;
        } else {
            memset(chFilePath, 0, MAX_PATH);
            if (pSubDir) {
                sprintf(chFilePath, "%s/%s", pSubDir, pstEnt->d_name);
            } else {
                sprintf(chFilePath, "%s", pstEnt->d_name);
            }

            nError = AddSubFile_my(hMpq, pRoot, chFilePath);
            assert(nError == ERROR_SUCCESS);
            if (nError != ERROR_SUCCESS)
                break;
        }
    }

    return nError;
}

int
CreateArchive_luascript(const char* pPlainName, const char* pScriptPath, int nMaxCount, LPBYTE pPassword) {
    assert(IsDir(pScriptPath));

	HANDLE hMpq = NULL;
	DWORD dwMaxFileCount = nMaxCount;

    DWORD dwStreamFlags = STREAM_PROVIDER_FLAT;
    if (pPassword) {
        dwStreamFlags = STREAM_PROVIDER_MPQE;
    }

	int nError;
	char chFullPath[MAX_PATH] = {0};

	CreateFullPathName_my(chFullPath, NULL, pPlainName);
	remove(chFullPath);

    if (!SFileCreateArchive(chFullPath, dwStreamFlags, dwMaxFileCount, &hMpq, pPassword)) {
        PRINT_MESSAGE("Failed to create archive %s", chFullPath);
        return GetLastError();
	}

    IteratorDirection(hMpq, pScriptPath, NULL);

	if (hMpq) {
		SFileCloseArchive(hMpq);
		hMpq = NULL;
	}

	return nError;
}

static TFileData *
LoadMpqFile_my(HANDLE hMpq, const char* pFileName) {
	TFileData *pFileData = NULL;
	HANDLE hFile;
	DWORD dwFileSizeHi = 0xCCCCCCCC;
	DWORD dwFileSizeLo = 0;
	DWORD dwBytesRead;
	int nError = ERROR_SUCCESS;

	PRINT_MESSAGE("Loading file %s ...", pFileName);

	if (!SFileOpenFileEx(hMpq, pFileName, 0, &hFile)) {
        PRINT_MESSAGE("Failed to open the file %s", pFileName);
        return NULL;
	}

	if (nError == ERROR_SUCCESS) {
		dwFileSizeLo = SFileGetFileSize(hFile, &dwFileSizeHi);
		if ((dwFileSizeLo == SFILE_INVALID_SIZE) || dwFileSizeHi != 0) {
            PRINT_MESSAGE("Failed to query the file size");
            return NULL;
		}
	}

	if (nError == ERROR_SUCCESS) {
		pFileData = (TFileData *)STORM_ALLOC(BYTE, sizeof(TFileData) + dwFileSizeLo);
		if (!pFileData) {
			PRINT_MESSAGE("Failed to allocate buffer for file %s content", pFileName);
			nError = ERROR_NOT_ENOUGH_MEMORY;
		}
	}

	if (nError == ERROR_SUCCESS) {
		memset(pFileData, 0, sizeof(TFileData) + dwFileSizeLo);
		pFileData->dwFileSize = dwFileSizeLo;
		if (!SFileGetFileInfo(hFile, SFileInfoFileIndex, &pFileData->dwBlockIndex, sizeof(DWORD), NULL)) {
			PRINT_MESSAGE("Failed retrieve the file index of %s", pFileName);
			nError = GetLastError();
		}
		if (!SFileGetFileInfo(hFile, SFileInfoFlags, &pFileData->dwFlags, sizeof(DWORD), NULL)) {
			PRINT_MESSAGE("Failed retrieve the file flags of %s", pFileName);
			nError = GetLastError();
		}
	}

	if (nError == ERROR_SUCCESS) {
		SFileReadFile(hFile, pFileData->FileData, dwFileSizeLo, &dwBytesRead, NULL);
		if (dwBytesRead != dwFileSizeLo) {
			PRINT_MESSAGE("Failed to read the content of the file %s", pFileName);
			nError = GetLastError();
		}
		// PRINT_MESSAGE("LoadMpqFile_my(%s) content: %s", pFileName, pFileData->FileData);
	}

	if (nError != ERROR_SUCCESS) {
		STORM_FREE(pFileData);
		SetLastError(nError);
		pFileData = NULL;
	}

	if (hFile != NULL) {
		SFileCloseFile(hFile);
	}
	return pFileData;
}
//
//int
//GetFilePatchCount_my(HANDLE hMpq, const char* pFileName) {
//	TCHAR *pPatchName;
//	HANDLE hFile;
//	TCHAR chPatchChain[0x400] = {0};
//	int nPatchCount = 0;
//	int nError = ERROR_SUCCESS;
//
//	if (SFileOpenFileEx(hMpq, pFileName, 0, &hFile)) {
//		pLogger->PrintProgress("Verifying patch chain for %s ....", pFileName);
//
//		if (!SFileGetFileInfo(hFile, SFileInfoPatchChain, chPatchChain, sizeof(chPatchChain), NULL))
//			nError = pLogger->PrintError("Failed to retrieve the patch chain on %s", pFileName);
//
//		if (nError == ERROR_SUCCESS && chPatchChain[0] == 0) {
//			pLogger->PrintError("the patch chain for %s is empty", pFileName);
//			nError = ERROR_FILE_CORRUPT;
//		}
//
//		if (nError == ERROR_SUCCESS) {
//			pPatchName = chPatchChain;
//			for(;;) {
//				pPatchName = pPatchName + _tcslen(pPatchName) + 1;
//				if (pPatchName[0] == 0)
//					break;
//
//				nPatchCount++;
//			}
//		}
//		SFileCloseFile(hFile);
//	} else {
//		pLogger->PrintError("Failed to open file %s", pFileName);
//	}
//
//	return nPatchCount;
//}

static int
SearchArchive_my(
	HANDLE hMpq,
	DWORD dwTestFlags,
	DWORD * pdwFileCount,
	LPBYTE pbFileHash = NULL) {
	SFILE_FIND_DATA sf;
	TFileData * pFileData = NULL;
	HANDLE hFind;
	DWORD dwFileCount = 0;
	hash_state md5state;

	bool bFound = true;
	int nError = ERROR_SUCCESS;

	md5_init(&md5state);

	PRINT_MESSAGE("search the archive ...");
	hFind = SFileFindFirstFile(hMpq, "*", &sf, NULL);
	if (hFind == NULL) {
		nError = GetLastError();
		return nError;
	}

	while(bFound) {
		dwFileCount++;

		if (dwTestFlags & TEST_FLAG_LOAD_FILES) {
			pFileData = LoadMpqFile_my(hMpq, sf.cFileName);
			if (pFileData != NULL) {
				if ((dwTestFlags & TEST_FLAG_HASH_FILES) && !IsInternalMpqFileName(sf.cFileName))
					md5_process(&md5state, pFileData->FileData, pFileData->dwFileSize);

				if ((dwTestFlags & TEST_FLAG_PLAY_WAVES) && strstr(sf.cFileName, ".wav") != NULL) {

				}

				STORM_FREE(pFileData);
			}
		}
		bFound = SFileFindNextFile(hFind, &sf);
	}

	SFileFindClose(hFind);

	if (pdwFileCount != NULL) {
		pdwFileCount[0] = dwFileCount;
	}

	if (pbFileHash != NULL && (dwTestFlags & TEST_FLAG_HASH_FILES)) {
		md5_done(&md5state, pbFileHash);
	}

	return nError;

}

int
OpenArchive_luascript(const char* pPlainName, LPBYTE pPassword, const char* pListFile) {
	TFileData *pFileData = NULL;
	HANDLE hMpq;
	DWORD dwFileCount = 0;
	DWORD dwTestFlags;
	char chListFileBuff[MAX_PATH] = {0};
	int nError = ERROR_SUCCESS;

	DWORD dwFlags = MPQ_OPEN_READ_ONLY;// | STREAM_PROVIDER_MPQE;
    if (pPassword) {
        dwFlags |= STREAM_PROVIDER_MPQE;
    }

    char chRealPath[MAX_PATH] = {0};
    CreateFullPathName_my(chRealPath, NULL, pPlainName);

 	if (!SFileOpenArchive(chRealPath, 0, dwFlags, &hMpq, pPassword)) {
 		nError = GetLastError();
 		if (nError == ERROR_AVI_FILE || nError == ERROR_FILE_INCOMPLETE)
 			return nError;

 		PRINT_MESSAGE("Failed to open archive %s", pPlainName);
 		return nError;
 	}
	if (nError == ERROR_SUCCESS) {
		if (pListFile != NULL) {
			PRINT_MESSAGE("Adding listfile %s ...", pListFile);
			CreateFullPathName_my(chListFileBuff, NULL, pListFile);
			nError = SFileAddListFile(hMpq, chListFileBuff);
			if (nError != ERROR_SUCCESS) {
				PRINT_MESSAGE("Failed to add the listfile to the MPQ");
			}
		}

		if (SFileHasFile(hMpq, LISTFILE_NAME)) {
			pFileData = LoadMpqFile_my(hMpq, LISTFILE_NAME);
			if (pFileData != NULL) {
				STORM_FREE(pFileData);
			}
		}

		if (SFileHasFile(hMpq, ATTRIBUTES_NAME)) {
			pFileData = LoadMpqFile_my(hMpq, ATTRIBUTES_NAME);
			if (pFileData != NULL) {
				STORM_FREE(pFileData);
			}
		}

		dwTestFlags = TEST_FLAG_LOAD_FILES;
		nError = SearchArchive_my(hMpq, dwTestFlags, &dwFileCount);
		SFileCloseArchive(hMpq);
	}

	return nError;
}

TFileData *
LoadCertainFile(const char* pPackage, const char* pFileName, LPBYTE pPassword) {
    HANDLE hMpq = NULL;
    TFileData* pstFileData = NULL;

    DWORD dwFlags = MPQ_OPEN_READ_ONLY;
    if (pPassword) {
        dwFlags |= STREAM_PROVIDER_MPQE;
    }

    if (!SFileOpenArchive(pPackage, 0, dwFlags, &hMpq, pPassword)) {
        SetLastError(ERROR_FILE_NOT_FOUND);
        return pstFileData;
    }

    if (SFileHasFile(hMpq, pFileName)) {
        pstFileData = LoadMpqFile_my(hMpq, pFileName);
        PRINT_MESSAGE("LoadCertainFile : \n%s", pstFileData->FileData);
    } else {
        SetLastError(ERROR_FILE_NOT_FOUND);
    }

    SFileCloseArchive(hMpq);
    hMpq = NULL;

    return pstFileData;
}

//
//int main(int argc, char * argv[])
//{
//    int nError = ERROR_SUCCESS;
//
//    memcpy(PACKET_PATH, root, strlen(root));
//
//    // Initialize storage and mix the random number generator
//    printf("==== Test Suite for StormLib version %s ====\n", STORMLIB_VERSION_STRING);
//
//    std::string script = "game.script";
//    char * path = "/Users/riddick/workspace/cocos2dx-20140301/projects/actgamejit_release/Resources/script_lc";
//    std::string path2 = "/Users/riddick/workspace/cocos2dx-20140301/projects/actgamejit/Resources/script";
//	CreateArchive_luascript(script.c_str(), path2.c_str(), 100, password);
//	OpenArchive_luascript(script.c_str(), password);
//
//    TFileData * pData = LoadCertainFile("/Users/riddick/StormLib/test/game.script", "Main.lua", password);
//    if (pData == NULL) {
//        printf("LOAD Main.lua failed \n");
//    }
//
//    STORM_FREE(pData);
//
//    printf("===== END =====\n");
//    return nError;
//
//}


text:
provdbconnector.utils package
=============================

Submodules
----------

provdbconnector.utils.converter module
--------------------------------------

.. automodule:: provdbconnector.utils.converter
    :members:
    :undoc-members:
    :show-inheritance:

provdbconnector.utils.serializer module
---------------------------------------

.. automodule:: provdbconnector.utils.serializer
    :members:
    :undoc-members:
    :show-inheritance:

provdbconnector.utils.validator module
--------------------------------------

.. automodule:: provdbconnector.utils.validator
    :members:
    :undoc-members:
    :show-inheritance:

Module contents
---------------

.. automodule:: provdbconnector.utils
    :members:
    :undoc-members:
    :show-inheritance: