text:
from __future__ import with_statement

import os, re, itertools
from cPickle import load, dump

from zope.interface import implements
from twisted.python import log, runtime
from twisted.persisted import styles
from buildbot import interfaces, util
from buildbot.util.lru import LRUCache
from buildbot.status.event import Event
from buildbot.status.build import BuildStatus
from buildbot.status.buildrequest import BuildRequestStatus

# user modules expect these symbols to be present here
from buildbot.status.results import SUCCESS, WARNINGS, FAILURE, SKIPPED
from buildbot.status.results import EXCEPTION, RETRY, Results, worst_status
_hush_pyflakes = [ SUCCESS, WARNINGS, FAILURE, SKIPPED,
                   EXCEPTION, RETRY, Results, worst_status ]

class BuilderStatus(styles.Versioned):
    """I handle status information for a single process.build.Builder object.
    That object sends status changes to me (frequently as Events), and I
    provide them on demand to the various status recipients, like the HTML
    waterfall display and the live status clients. It also sends build
    summaries to me, which I log and provide to status clients who aren't
    interested in seeing details of the individual build steps.

    I am responsible for maintaining the list of historic Events and Builds,
    pruning old ones, and loading them from / saving them to disk.

    I live in the buildbot.process.build.Builder object, in the
    .builder_status attribute.

    @type  category: string
    @ivar  category: user-defined category this builder belongs to; can be
                     used to filter on in status clients
    """

    implements(interfaces.IBuilderStatus, interfaces.IEventSource)

    persistenceVersion = 1
    persistenceForgets = ( 'wasUpgraded', )

    category = None
    currentBigState = "offline" # or idle/waiting/interlocked/building
    basedir = None # filled in by our parent

    def __init__(self, buildername, category, master, description):
        self.name = buildername
        self.category = category
        self.description = description
        self.master = master

        self.slavenames = []
        self.events = []
        # these three hold Events, and are used to retrieve the current
        # state of the boxes.
        self.lastBuildStatus = None
        #self.currentBig = None
        #self.currentSmall = None
        self.currentBuilds = []
        self.nextBuild = None
        self.watchers = []
        self.buildCache = LRUCache(self.cacheMiss)

    # persistence

    def __getstate__(self):
        # when saving, don't record transient stuff like what builds are
        # currently running, because they won't be there when we start back
        # up. Nor do we save self.watchers, nor anything that gets set by our
        # parent like .basedir and .status
        d = styles.Versioned.__getstate__(self)
        d['watchers'] = []
        del d['buildCache']
        for b in self.currentBuilds:
            b.saveYourself()
            # TODO: push a 'hey, build was interrupted' event
        del d['currentBuilds']
        d.pop('pendingBuilds', None)
        del d['currentBigState']
        del d['basedir']
        del d['status']
        del d['nextBuildNumber']
        del d['master']
        return d

    def __setstate__(self, d):
        # when loading, re-initialize the transient stuff. Remember that
        # upgradeToVersion1 and such will be called after this finishes.
        styles.Versioned.__setstate__(self, d)
        self.buildCache = LRUCache(self.cacheMiss)
        self.currentBuilds = []
        self.watchers = []
        self.slavenames = []
        # self.basedir must be filled in by our parent
        # self.status must be filled in by our parent
        # self.master must be filled in by our parent

    def upgradeToVersion1(self):
        if hasattr(self, 'slavename'):
            self.slavenames = [self.slavename]
            del self.slavename
        if hasattr(self, 'nextBuildNumber'):
            del self.nextBuildNumber # determineNextBuildNumber chooses this
        self.wasUpgraded = True

    def determineNextBuildNumber(self):
        """Scan our directory of saved BuildStatus instances to determine
        what our self.nextBuildNumber should be. Set it one larger than the
        highest-numbered build we discover. This is called by the top-level
        Status object shortly after we are created or loaded from disk.
        """
        existing_builds = [int(f)
                           for f in os.listdir(self.basedir)
                           if re.match("^\d+$", f)]
        if existing_builds:
            self.nextBuildNumber = max(existing_builds) + 1
        else:
            self.nextBuildNumber = 0

    def saveYourself(self):
        for b in self.currentBuilds:
            if not b.isFinished:
                # interrupted build, need to save it anyway.
                # BuildStatus.saveYourself will mark it as interrupted.
                b.saveYourself()
        filename = os.path.join(self.basedir, "builder")
        tmpfilename = filename + ".tmp"
        try:
            with open(tmpfilename, "wb") as f:
                dump(self, f, -1)
            if runtime.platformType  == 'win32':
                # windows cannot rename a file on top of an existing one
                if os.path.exists(filename):
                    os.unlink(filename)
            os.rename(tmpfilename, filename)
        except:
            log.msg("unable to save builder %s" % self.name)
            log.err()

    # build cache management

    def setCacheSize(self, size):
        self.buildCache.set_max_size(size)

    def makeBuildFilename(self, number):
        return os.path.join(self.basedir, "%d" % number)

    def getBuildByNumber(self, number):
        return self.buildCache.get(number)

    def loadBuildFromFile(self, number):
        filename = self.makeBuildFilename(number)
        try:
            log.msg("Loading builder %s's build %d from on-disk pickle"
                % (self.name, number))
            with open(filename, "rb") as f:
                build = load(f)
            build.setProcessObjects(self, self.master)

            # (bug #1068) if we need to upgrade, we probably need to rewrite
            # this pickle, too.  We determine this by looking at the list of
            # Versioned objects that have been unpickled, and (after doUpgrade)
            # checking to see if any of them set wasUpgraded.  The Versioneds'
            # upgradeToVersionNN methods all set this.
            versioneds = styles.versionedsToUpgrade
            styles.doUpgrade()
            if True in [ hasattr(o, 'wasUpgraded') for o in versioneds.values() ]:
                log.msg("re-writing upgraded build pickle")
                build.saveYourself()

            # check that logfiles exist
            build.checkLogfiles()
            return build
        except IOError:
            raise IndexError("no such build %d" % number)
        except EOFError:
            raise IndexError("corrupted build pickle %d" % number)

    def cacheMiss(self, number, **kwargs):
        # If kwargs['val'] exists, this is a new value being added to
        # the cache.  Just return it.
        if 'val' in kwargs:
            return kwargs['val']

        # first look in currentBuilds
        for b in self.currentBuilds:
            if b.number == number:
                return b

        # then fall back to loading it from disk
        return self.loadBuildFromFile(number)

    def prune(self, events_only=False):
        # begin by pruning our own events
        eventHorizon = self.master.config.eventHorizon
        self.events = self.events[-eventHorizon:]

        if events_only:
            return

        # get the horizons straight
        buildHorizon = self.master.config.buildHorizon
        if buildHorizon is not None:
            earliest_build = self.nextBuildNumber - buildHorizon
        else:
            earliest_build = 0

        logHorizon = self.master.config.logHorizon
        if logHorizon is not None:
            earliest_log = self.nextBuildNumber - logHorizon
        else:
            earliest_log = 0

        if earliest_log < earliest_build:
            earliest_log = earliest_build

        if earliest_build == 0:
            return

        # skim the directory and delete anything that shouldn't be there anymore
        build_re = re.compile(r"^([0-9]+)$")
        build_log_re = re.compile(r"^([0-9]+)-.*$")
        # if the directory doesn't exist, bail out here
        if not os.path.exists(self.basedir):
            return

        for filename in os.listdir(self.basedir):
            num = None
            mo = build_re.match(filename)
            is_logfile = False
            if mo:
                num = int(mo.group(1))
            else:
                mo = build_log_re.match(filename)
                if mo:
                    num = int(mo.group(1))
                    is_logfile = True

            if num is None: continue
            if num in self.buildCache.cache: continue

            if (is_logfile and num < earliest_log) or num < earliest_build:
                pathname = os.path.join(self.basedir, filename)
                log.msg("pruning '%s'" % pathname)
                try: os.unlink(pathname)
                except OSError: pass

    # IBuilderStatus methods
    def getName(self):
        # if builderstatus page does show not up without any reason then
        # str(self.name) may be a workaround
        return self.name

    def setDescription(self, description):
        # used during reconfig
        self.description = description

    def getDescription(self):
        return self.description

    def getState(self):
        return (self.currentBigState, self.currentBuilds)

    def getSlaves(self):
        return [self.status.getSlave(name) for name in self.slavenames]

    def getPendingBuildRequestStatuses(self):
        db = self.status.master.db
        d = db.buildrequests.getBuildRequests(claimed=False,
                                              buildername=self.name)
        def make_statuses(brdicts):
            return [BuildRequestStatus(self.name, brdict['brid'],
                                       self.status)
                    for brdict in brdicts]
        d.addCallback(make_statuses)
        return d

    def getCurrentBuilds(self):
        return self.currentBuilds

    def getLastFinishedBuild(self):
        b = self.getBuild(-1)
        if not (b and b.isFinished()):
            b = self.getBuild(-2)
        return b

    def setCategory(self, category):
        # used during reconfig
        self.category = category

    def getCategory(self):
        return self.category

    def getBuild(self, number):
        if number < 0:
            number = self.nextBuildNumber + number
        if number < 0 or number >= self.nextBuildNumber:
            return None

        try:
            return self.getBuildByNumber(number)
        except IndexError:
            return None

    def getEvent(self, number):
        try:
            return self.events[number]
        except IndexError:
            return None

    def _getBuildBranches(self, build):
        return set([ ss.branch
            for ss in build.getSourceStamps() ])

    def generateFinishedBuilds(self, branches=[],
                               num_builds=None,
                               max_buildnum=None,
                               finished_before=None,
                               results=None,
                               max_search=200):
        got = 0
        branches = set(branches)
        for Nb in itertools.count(1):
            if Nb > self.nextBuildNumber:
                break
            if Nb > max_search:
                break
            build = self.getBuild(-Nb)
            if build is None:
                continue
            if max_buildnum is not None:
                if build.getNumber() > max_buildnum:
                    continue
            if not build.isFinished():
                continue
            if finished_before is not None:
                start, end = build.getTimes()
                if end >= finished_before:
                    continue
            # if we were asked to filter on branches, and none of the
            # sourcestamps match, skip this build
            if branches and not branches & self._getBuildBranches(build):
                continue
            if results is not None:
                if build.getResults() not in results:
                    continue
            got += 1
            yield build
            if num_builds is not None:
                if got >= num_builds:
                    return

    def eventGenerator(self, branches=[], categories=[], committers=[], minTime=0):
        """This function creates a generator which will provide all of this
        Builder's status events, starting with the most recent and
        progressing backwards in time. """

        # remember the oldest-to-earliest flow here. "next" means earlier.

        # TODO: interleave build steps and self.events by timestamp.
        # TODO: um, I think we're already doing that.

        # TODO: there's probably something clever we could do here to
        # interleave two event streams (one from self.getBuild and the other
        # from self.getEvent), which would be simpler than this control flow

        eventIndex = -1
        e = self.getEvent(eventIndex)
        branches = set(branches)
        for Nb in range(1, self.nextBuildNumber+1):
            b = self.getBuild(-Nb)
            if not b:
                # HACK: If this is the first build we are looking at, it is
                # possible it's in progress but locked before it has written a
                # pickle; in this case keep looking.
                if Nb == 1:
                    continue
                break
            if b.getTimes()[0] < minTime:
                break
            # if we were asked to filter on branches, and none of the
            # sourcestamps match, skip this build
            if branches and not branches & self._getBuildBranches(b):
                continue
            if categories and not b.getBuilder().getCategory() in categories:
                continue
            if committers and not [True for c in b.getChanges() if c.who in committers]:
                continue
            steps = b.getSteps()
            for Ns in range(1, len(steps)+1):
                if steps[-Ns].started:
                    step_start = steps[-Ns].getTimes()[0]
                    while e is not None and e.getTimes()[0] > step_start:
                        yield e
                        eventIndex -= 1
                        e = self.getEvent(eventIndex)
                    yield steps[-Ns]
            yield b
        while e is not None:
            yield e
            eventIndex -= 1
            e = self.getEvent(eventIndex)
            if e and e.getTimes()[0] < minTime:
                break

    def subscribe(self, receiver):
        # will get builderChangedState, buildStarted, buildFinished,
        # requestSubmitted, requestCancelled. Note that a request which is
        # resubmitted (due to a slave disconnect) will cause requestSubmitted
        # to be invoked multiple times.
        self.watchers.append(receiver)
        self.publishState(receiver)
        # our parent Status provides requestSubmitted and requestCancelled
        self.status._builder_subscribe(self.name, receiver)

    def unsubscribe(self, receiver):
        self.watchers.remove(receiver)
        self.status._builder_unsubscribe(self.name, receiver)

    ## Builder interface (methods called by the Builder which feeds us)

    def setSlavenames(self, names):
        self.slavenames = names

    def addEvent(self, text=[]):
        # this adds a duration event. When it is done, the user should call
        # e.finish(). They can also mangle it by modifying .text
        e = Event()
        e.started = util.now()
        e.text = text
        self.events.append(e)
        self.prune(events_only=True)
        return e # they are free to mangle it further

    def addPointEvent(self, text=[]):
        # this adds a point event, one which occurs as a single atomic
        # instant of time.
        e = Event()
        e.started = util.now()
        e.finished = 0
        e.text = text
        self.events.append(e)
        self.prune(events_only=True)
        return e # for consistency, but they really shouldn't touch it

    def setBigState(self, state):
        needToUpdate = state != self.currentBigState
        self.currentBigState = state
        if needToUpdate:
            self.publishState()

    def publishState(self, target=None):
        state = self.currentBigState

        if target is not None:
            # unicast
            target.builderChangedState(self.name, state)
            return
        for w in self.watchers:
            try:
                w.builderChangedState(self.name, state)
            except:
                log.msg("Exception caught publishing state to %r" % w)
                log.err()

    def newBuild(self):
        """The Builder has decided to start a build, but the Build object is
        not yet ready to report status (it has not finished creating the
        Steps). Create a BuildStatus object that it can use."""
        number = self.nextBuildNumber
        self.nextBuildNumber += 1
        # TODO: self.saveYourself(), to make sure we don't forget about the
        # build number we've just allocated. This is not quite as important
        # as it was before we switch to determineNextBuildNumber, but I think
        # it may still be useful to have the new build save itself.
        s = BuildStatus(self, self.master, number)
        s.waitUntilFinished().addCallback(self._buildFinished)
        return s

    # buildStarted is called by our child BuildStatus instances
    def buildStarted(self, s):
        """Now the BuildStatus object is ready to go (it knows all of its
        Steps, its ETA, etc), so it is safe to notify our watchers."""

        assert s.builder is self # paranoia
        assert s not in self.currentBuilds
        self.currentBuilds.append(s)
        self.buildCache.get(s.number, val=s)

        # now that the BuildStatus is prepared to answer queries, we can
        # announce the new build to all our watchers

        for w in self.watchers: # TODO: maybe do this later? callLater(0)?
            try:
                receiver = w.buildStarted(self.getName(), s)
                if receiver:
                    if type(receiver) == type(()):
                        s.subscribe(receiver[0], receiver[1])
                    else:
                        s.subscribe(receiver)
                    d = s.waitUntilFinished()
                    d.addCallback(lambda s: s.unsubscribe(receiver))
            except:
                log.msg("Exception caught notifying %r of buildStarted event" % w)
                log.err()

    def _buildFinished(self, s):
        assert s in self.currentBuilds
        s.saveYourself()
        self.currentBuilds.remove(s)

        name = self.getName()
        results = s.getResults()
        for w in self.watchers:
            try:
                w.buildFinished(name, s, results)
            except:
                log.msg("Exception caught notifying %r of buildFinished event" % w)
                log.err()

        self.prune() # conserve disk

    def asDict(self):
        result = {}
        # Constant
        # TODO(maruel): Fix me. We don't want to leak the full path.
        result['basedir'] = os.path.basename(self.basedir)
        result['category'] = self.category
        result['slaves'] = self.slavenames
        result['schedulers'] = [ s.name
                for s in self.status.master.allSchedulers()
                if self.name in s.builderNames ]
        #result['url'] = self.parent.getURLForThing(self)
        # TODO(maruel): Add cache settings? Do we care?

        # Transient
        # Collect build numbers.
        # Important: Only grab the *cached* builds numbers to reduce I/O.
        current_builds = [b.getNumber() for b in self.currentBuilds]
        cached_builds = list(set(self.buildCache.keys() + current_builds))
        cached_builds.sort()
        result['cachedBuilds'] = cached_builds
        result['currentBuilds'] = current_builds
        result['state'] = self.getState()[0]
        # lies, but we don't have synchronous access to this info; use
        # asDict_async instead
        result['pendingBuilds'] = 0
        return result

    def asDict_async(self):
        """Just like L{asDict}, but with a nonzero pendingBuilds."""
        result = self.asDict()
        d = self.getPendingBuildRequestStatuses()
        def combine(statuses):
            result['pendingBuilds'] = len(statuses)
            return result
        d.addCallback(combine)
        return d

    def getMetrics(self):
        return self.botmaster.parent.metrics

# vim: set ts=4 sts=4 sw=4 et:


text:
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="ChangeListManager">
    <list default="true" id="1e971f4c-3093-4ea0-ac0a-37a6e9c61707" name="Default" comment="">
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$ClearClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$ClearClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$DivideClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$DivideClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$EightClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$EightClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$EqualsClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$EqualsClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$FiveClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$FiveClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$FourClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$FourClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$MinusClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$MinusClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$MultiplyClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$MultiplyClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$NineClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$NineClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$OneClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$OneClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$PlusClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$PlusClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$SevenClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$SevenClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$SixClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$SixClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$ThreeClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$ThreeClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$TwoClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$TwoClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$ZeroClick.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator$ZeroClick.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator.class" afterPath="$PROJECT_DIR$/out/production/Calculator/com/nuiofrd/ScreenGenerator.class" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java" afterPath="$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/vcs.xml" afterPath="$PROJECT_DIR$/.idea/vcs.xml" />
      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
    </list>
    <ignored path="Calculator.iws" />
    <ignored path=".idea/workspace.xml" />
    <ignored path="$PROJECT_DIR$/out/" />
    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
    <option name="TRACKING_ENABLED" value="true" />
    <option name="SHOW_DIALOG" value="false" />
    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    <option name="LAST_RESOLUTION" value="IGNORE" />
  </component>
  <component name="ChangesViewManager" flattened_view="true" show_ignored="false" />
  <component name="Commander">
    <leftPanel />
    <rightPanel />
    <splitter proportion="0.5" />
  </component>
  <component name="CreatePatchCommitExecutor">
    <option name="PATCH_PATH" value="" />
  </component>
  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
  <component name="FavoritesManager">
    <favorites_list name="Calculator" />
  </component>
  <component name="FileEditorManager">
    <leaf>
      <file leaf-file-name="Main.java" pinned="false" current-in-tab="false">
        <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="0.0">
              <caret line="9" column="8" selection-start-line="9" selection-start-column="8" selection-end-line="19" selection-end-column="35" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
      <file leaf-file-name="ScreenGenerator.java" pinned="false" current-in-tab="true">
        <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java">
          <provider selected="true" editor-type-id="text-editor">
            <state vertical-scroll-proportion="-1.0190736">
              <caret line="13" column="13" selection-start-line="13" selection-start-column="13" selection-end-line="13" selection-end-column="13" />
              <folding />
            </state>
          </provider>
        </entry>
      </file>
    </leaf>
  </component>
  <component name="FindManager">
    <FindUsagesManager>
      <setting name="OPEN_NEW_TAB" value="true" />
    </FindUsagesManager>
  </component>
  <component name="Git.Settings">
    <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
  </component>
  <component name="GradleLocalSettings">
    <option name="externalProjectsViewState">
      <projects_view />
    </option>
  </component>
  <component name="IdeDocumentHistory">
    <option name="CHANGED_PATHS">
      <list>
        <option value="$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java" />
        <option value="$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java" />
      </list>
    </option>
  </component>
  <component name="MavenProjectNavigator">
    <treeState />
  </component>
  <component name="NamedScopeManager">
    <order />
  </component>
  <component name="ProjectFrameBounds">
    <option name="x" value="683" />
    <option name="width" value="683" />
    <option name="height" value="728" />
  </component>
  <component name="ProjectLevelVcsManager" settingsEditedManually="true">
    <OptionsSetting value="true" id="Add" />
    <OptionsSetting value="true" id="Remove" />
    <OptionsSetting value="true" id="Checkout" />
    <OptionsSetting value="true" id="Update" />
    <OptionsSetting value="true" id="Status" />
    <OptionsSetting value="true" id="Edit" />
    <ConfirmationsSetting value="0" id="Add" />
    <ConfirmationsSetting value="0" id="Remove" />
  </component>
  <component name="ProjectReloadState">
    <option name="STATE" value="0" />
  </component>
  <component name="ProjectView">
    <navigator currentView="ProjectPane" proportions="" version="1">
      <flattenPackages />
      <showMembers />
      <showModules />
      <showLibraryContents />
      <hideEmptyPackages />
      <abbreviatePackageNames />
      <autoscrollToSource />
      <autoscrollFromSource />
      <sortByType />
    </navigator>
    <panes>
      <pane id="Scope" />
      <pane id="Scratches" />
      <pane id="PackagesPane" />
      <pane id="ProjectPane">
        <subPane>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="Calculator" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="Calculator" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="Calculator" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
          <PATH>
            <PATH_ELEMENT>
              <option name="myItemId" value="Calculator" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="Calculator" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="src" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
            <PATH_ELEMENT>
              <option name="myItemId" value="nuiofrd" />
              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
            </PATH_ELEMENT>
          </PATH>
        </subPane>
      </pane>
    </panes>
  </component>
  <component name="PropertiesComponent">
    <property name="GoToClass.includeLibraries" value="false" />
    <property name="GoToClass.toSaveIncludeLibraries" value="false" />
    <property name="GoToFile.includeJavaFiles" value="false" />
    <property name="MemberChooser.sorted" value="false" />
    <property name="MemberChooser.showClasses" value="true" />
    <property name="MemberChooser.copyJavadoc" value="false" />
    <property name="recentsLimit" value="5" />
    <property name="dynamic.classpath" value="false" />
    <property name="FullScreen" value="false" />
    <property name="OverrideImplement.combined" value="true" />
    <property name="OverrideImplement.overriding.sorted" value="false" />
    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
  </component>
  <component name="RecentsManager">
    <key name="CopyFile.RECENT_KEYS">
      <recent name="C:\Users\Brenden Bunker\IdeaProjects\Calculator\src" />
    </key>
    <key name="MoveFile.RECENT_KEYS">
      <recent name="C:\Users\Brenden Bunker\IdeaProjects\Calculator\src\com\nuiofrd" />
    </key>
    <key name="CopyClassDialog.RECENTS_KEY">
      <recent name="com.nuiofrd" />
    </key>
  </component>
  <component name="RunManager" selected="Application.Main">
    <configuration default="false" name="Main" type="Application" factoryName="Application" temporary="true">
      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
      <option name="MAIN_CLASS_NAME" value="com.nuiofrd.Main" />
      <option name="VM_PARAMETERS" value="" />
      <option name="PROGRAM_PARAMETERS" value="" />
      <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
      <option name="ALTERNATIVE_JRE_PATH" value="" />
      <option name="ENABLE_SWING_INSPECTOR" value="false" />
      <option name="ENV_VARIABLES" />
      <option name="PASS_PARENT_ENVS" value="true" />
      <module name="Calculator" />
      <envs />
      <RunnerSettings RunnerId="Debug">
        <option name="DEBUG_PORT" value="" />
        <option name="TRANSPORT" value="0" />
        <option name="LOCAL" value="true" />
      </RunnerSettings>
      <RunnerSettings RunnerId="Run" />
      <ConfigurationWrapper RunnerId="Debug" />
      <ConfigurationWrapper RunnerId="Run" />
      <method />
    </configuration>
    <configuration default="true" type="AndroidRunConfigurationType" factoryName="Android Application">
      <module name="" />
      <option name="ACTIVITY_CLASS" value="" />
      <option name="MODE" value="default_activity" />
      <option name="DEPLOY" value="true" />
      <option name="ARTIFACT_NAME" value="" />
      <option name="TARGET_SELECTION_MODE" value="EMULATOR" />
      <option name="USE_LAST_SELECTED_DEVICE" value="false" />
      <option name="PREFERRED_AVD" value="" />
      <option name="USE_COMMAND_LINE" value="true" />
      <option name="COMMAND_LINE" value="" />
      <option name="WIPE_USER_DATA" value="false" />
      <option name="DISABLE_BOOT_ANIMATION" value="false" />
      <option name="NETWORK_SPEED" value="full" />
      <option name="NETWORK_LATENCY" value="none" />
      <option name="CLEAR_LOGCAT" value="false" />
      <option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
      <option name="FILTER_LOGCAT_AUTOMATICALLY" value="true" />
      <method />
    </configuration>
    <configuration default="true" type="AndroidTestRunConfigurationType" factoryName="Android Tests">
      <module name="" />
      <option name="TESTING_TYPE" value="0" />
      <option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
      <option name="METHOD_NAME" value="" />
      <option name="CLASS_NAME" value="" />
      <option name="PACKAGE_NAME" value="" />
      <option name="TARGET_SELECTION_MODE" value="EMULATOR" />
      <option name="USE_LAST_SELECTED_DEVICE" value="false" />
      <option name="PREFERRED_AVD" value="" />
      <option name="USE_COMMAND_LINE" value="true" />
      <option name="COMMAND_LINE" value="" />
      <option name="WIPE_USER_DATA" value="false" />
      <option name="DISABLE_BOOT_ANIMATION" value="false" />
      <option name="NETWORK_SPEED" value="full" />
      <option name="NETWORK_LATENCY" value="none" />
      <option name="CLEAR_LOGCAT" value="false" />
      <option name="SHOW_LOGCAT_AUTOMATICALLY" value="true" />
      <option name="FILTER_LOGCAT_AUTOMATICALLY" value="true" />
      <method />
    </configuration>
    <configuration default="true" type="Application" factoryName="Application">
      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
      <option name="MAIN_CLASS_NAME" />
      <option name="VM_PARAMETERS" />
      <option name="PROGRAM_PARAMETERS" />
      <option name="WORKING_DIRECTORY" />
      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
      <option name="ALTERNATIVE_JRE_PATH" />
      <option name="ENABLE_SWING_INSPECTOR" value="false" />
      <option name="ENV_VARIABLES" />
      <option name="PASS_PARENT_ENVS" value="true" />
      <module name="" />
      <envs />
      <method />
    </configuration>
    <configuration default="true" type="JUnit" factoryName="JUnit">
      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
      <module name="" />
      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
      <option name="ALTERNATIVE_JRE_PATH" />
      <option name="PACKAGE_NAME" />
      <option name="MAIN_CLASS_NAME" />
      <option name="METHOD_NAME" />
      <option name="TEST_OBJECT" value="class" />
      <option name="VM_PARAMETERS" />
      <option name="PARAMETERS" />
      <option name="WORKING_DIRECTORY" />
      <option name="ENV_VARIABLES" />
      <option name="PASS_PARENT_ENVS" value="true" />
      <option name="TEST_SEARCH_SCOPE">
        <value defaultName="moduleWithDependencies" />
      </option>
      <envs />
      <patterns />
      <method />
    </configuration>
    <configuration default="true" type="TestNG" factoryName="TestNG">
      <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
      <module name="" />
      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
      <option name="ALTERNATIVE_JRE_PATH" />
      <option name="SUITE_NAME" />
      <option name="PACKAGE_NAME" />
      <option name="MAIN_CLASS_NAME" />
      <option name="METHOD_NAME" />
      <option name="GROUP_NAME" />
      <option name="TEST_OBJECT" value="CLASS" />
      <option name="VM_PARAMETERS" />
      <option name="PARAMETERS" />
      <option name="WORKING_DIRECTORY" />
      <option name="OUTPUT_DIRECTORY" />
      <option name="ANNOTATION_TYPE" />
      <option name="ENV_VARIABLES" />
      <option name="PASS_PARENT_ENVS" value="true" />
      <option name="TEST_SEARCH_SCOPE">
        <value defaultName="moduleWithDependencies" />
      </option>
      <option name="USE_DEFAULT_REPORTERS" value="false" />
      <option name="PROPERTIES_FILE" />
      <envs />
      <properties />
      <listeners />
      <method />
    </configuration>
    <list size="1">
      <item index="0" class="java.lang.String" itemvalue="Application.Main" />
    </list>
    <recent_temporary>
      <list size="1">
        <item index="0" class="java.lang.String" itemvalue="Application.Main" />
      </list>
    </recent_temporary>
  </component>
  <component name="ShelveChangesManager" show_recycled="false" />
  <component name="SvnConfiguration">
    <configuration />
  </component>
  <component name="TaskManager">
    <task active="true" id="Default" summary="Default task">
      <changelist id="1e971f4c-3093-4ea0-ac0a-37a6e9c61707" name="Default" comment="" />
      <created>1413760960590</created>
      <option name="number" value="Default" />
      <updated>1413760960590</updated>
    </task>
    <servers />
  </component>
  <component name="ToolWindowManager">
    <frame x="683" y="0" width="683" height="728" extended-state="0" />
    <editor active="true" />
    <layout>
      <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32879046" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" />
      <window_info id="Palette	" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
      <window_info id="Application Servers" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Maven Projects" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32980332" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33724833" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Designer" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3258427" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.24962178" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
      <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.0" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
      <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    </layout>
  </component>
  <component name="Vcs.Log.UiProperties">
    <option name="RECENTLY_FILTERED_USER_GROUPS">
      <collection />
    </option>
    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
      <collection />
    </option>
  </component>
  <component name="VcsContentAnnotationSettings">
    <option name="myLimit" value="2678400000" />
  </component>
  <component name="XDebuggerManager">
    <breakpoint-manager>
      <option name="time" value="1" />
    </breakpoint-manager>
    <watches-manager />
  </component>
  <component name="antWorkspaceConfiguration">
    <option name="IS_AUTOSCROLL_TO_SOURCE" value="false" />
    <option name="FILTER_TARGETS" value="false" />
  </component>
  <component name="editorHistoryManager">
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="9" column="8" selection-start-line="9" selection-start-column="8" selection-end-line="19" selection-end-column="35" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="8" column="0" selection-start-line="8" selection-start-column="0" selection-end-line="19" selection-end-column="35" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="22" column="0" selection-start-line="22" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="117" selection-start-line="13" selection-start-column="117" selection-end-line="13" selection-end-column="117" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="117" selection-start-line="13" selection-start-column="117" selection-end-line="13" selection-end-column="117" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="115" column="0" selection-start-line="115" selection-start-column="0" selection-end-line="115" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="143" column="105" selection-start-line="143" selection-start-column="105" selection-end-line="143" selection-end-column="105" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="143" column="105" selection-start-line="143" selection-start-column="105" selection-end-line="143" selection-end-column="105" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="105" column="17" selection-start-line="105" selection-start-column="17" selection-end-line="105" selection-end-column="17" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="13" column="30" selection-start-line="13" selection-start-column="30" selection-end-line="13" selection-end-column="30" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="120" column="5" selection-start-line="120" selection-start-column="5" selection-end-line="120" selection-end-column="5" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="12" column="0" selection-start-line="12" selection-start-column="0" selection-end-line="17" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="246" column="15" selection-start-line="246" selection-start-column="15" selection-end-line="298" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="12" column="0" selection-start-line="12" selection-start-column="0" selection-end-line="17" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="246" column="15" selection-start-line="246" selection-start-column="15" selection-end-line="298" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="246" column="15" selection-start-line="246" selection-start-column="15" selection-end-line="298" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="298" column="0" selection-start-line="298" selection-start-column="0" selection-end-line="298" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="233" column="12" selection-start-line="233" selection-start-column="12" selection-end-line="233" selection-end-column="12" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="22" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="233" column="12" selection-start-line="233" selection-start-column="12" selection-end-line="233" selection-end-column="12" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="15" column="13" selection-start-line="15" selection-start-column="13" selection-end-line="15" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="291" column="24" selection-start-line="291" selection-start-column="24" selection-end-line="291" selection-end-column="24" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="15" column="13" selection-start-line="15" selection-start-column="13" selection-end-line="15" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="291" column="24" selection-start-line="291" selection-start-column="24" selection-end-line="291" selection-end-column="24" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="15" column="13" selection-start-line="15" selection-start-column="13" selection-end-line="15" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="15" column="13" selection-start-line="15" selection-start-column="13" selection-end-line="15" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="259" column="0" selection-start-line="259" selection-start-column="0" selection-end-line="259" selection-end-column="0" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="15" column="13" selection-start-line="15" selection-start-column="13" selection-end-line="15" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="26" column="38" selection-start-line="26" selection-start-column="38" selection-end-line="26" selection-end-column="38" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="8" column="0" selection-start-line="8" selection-start-column="0" selection-end-line="8" selection-end-column="0" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="14" column="8" selection-start-line="14" selection-start-column="8" selection-end-line="14" selection-end-column="8" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$USER_HOME$/IdeaProjects/Sodoku/Java/com/brendenbunker/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.5377856">
          <caret line="40" column="30" selection-start-line="40" selection-start-column="30" selection-end-line="40" selection-end-column="30" />
          <folding>
            <element signature="imports" expanded="false" />
          </folding>
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/Main.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="0.0">
          <caret line="9" column="8" selection-start-line="9" selection-start-column="8" selection-end-line="19" selection-end-column="35" />
          <folding />
        </state>
      </provider>
    </entry>
    <entry file="file://$PROJECT_DIR$/src/com/nuiofrd/ScreenGenerator.java">
      <provider selected="true" editor-type-id="text-editor">
        <state vertical-scroll-proportion="-1.0190736">
          <caret line="13" column="13" selection-start-line="13" selection-start-column="13" selection-end-line="13" selection-end-column="13" />
          <folding />
        </state>
      </provider>
    </entry>
  </component>
</project>

redpajama_set_name: RedPajamaGithub


text:
The users of your app can interact with [controls](~/pages/concepts/dothtml-markup/builtin-controls) in the page.

The most common action is clicking on a [Button](~/controls/builtin/Button) or [LinkButton](~/controls/builtin/LinkButton) control. However, there are other kinds of events which the app will want to handle, like changing the value in the [TextBox](~/controls/builtin/TextBox) or selecting an item in a [ComboBox](~/controls/builtin/ComboBox).

In **DotVVM**, there are two main ways of handling such events:

* [Commands](commands): If you use command, the entire viewmodel is sent to the server and the command method will be invoked. If the method changes the state of the viewmodel, these changes are sent back to the client, and the page is updated accordingly.

# [CommandSample.dothtml](#tab/command-view)

```DOTHTML
<dot:ComboBox SelectedValue="{value: Location}" ... />

<p>Current temperature: {{value: Weather.Temperature}} °C</p>
<p>Conditions: {{value: Weather.Conditions}}</p>

<dot:Button Text="Refresh weather" Click="{command: Refresh()}" />
```

# [CommandSampleViewModel.cs](#tab/command-viewmodel)

```CSHARP
public class CommandSampleViewModel
{
    public string Location { get; set; }

    public WeatherInfo Weather { get; set; }

    public async Task Refresh()
    {
        // you can access any information from the viewmodel
        Weather = _weatherService.GetWeather(Location);
    }
}
```

***

* [Static commands](static-commands): Static commands can make local changes to the viewmodel (assign values to properties, call methods that can be translated to JavaScript by DotVVM, or call methods on the server and use the result to update some viewmodel properties).

# [CommandSample.dothtml](#tab/staticcommand-view)

```DOTHTML
@service _weatherService = MyApp.Services.WeatherService

<dot:ComboBox SelectedValue="{value: Location}" ... />

<p>Current temperature: {{value: Weather.Temperature}} °C</p>
<p>Conditions: {{value: Weather.Conditions}}</p>

<!-- You need to pass all arguments to the called method - the viewmodel is not sent to the server -->
<dot:Button Text="Increment" Click="{staticCommand: Weather = _weatherService.GetWeather(Location)}" />
```

# [CommandSampleViewModel.cs](#tab/staticcommand-viewmodel)

```CSHARP
public class CommandSampleViewModel
{
    public string Location { get; set; }

    public WeatherInfo Weather { get; set; }
}
```

***

DotVVM handles the client-to-server communication automatically, and uses the browser `fetch` API. There are no full page reloads or classic form POSTs in DotVVM - both commands and static commands communicate via AJAX. This is a difference between DotVVM and [Razor Pages](https://docs.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-5.0&tabs=visual-studio) which also offer MVVM way of development.

## When to use command and static command

Commands and static commands are completely different concepts which both have their advantages and disadvantages. Some users prefer one of these concepts, others like to combine and use them together.

### Commands

[Commands](commands) treat the viewmodel as one "atomic" piece of information. When you invoke a command, the viewmodel is sent to the server where the command method is invoked. The changes made to the viewmodel are then sent back to the browser, and applied to the page.

Commands are present in the framework from its first version, and they are popular mostly because they are simple to use. Also, commands offer plenty of features like [validation](~/pages/concepts/validation/overview), [action filters](~/pages/concepts/viewmodels/filters/overview), which are not available when you use static commands.

However, commands come with some overhead:

* In most cases, it isn't necessary to transmit the entire viewmodel to the server - the invoked method typically needs just a few properties. This can be eliminated by using [server-side viewmodel cache](~/pages/concepts/viewmodels/server-side-viewmodel-cache) or by using the [Bind attribute](~/pages/concepts/viewmodels/binding-direction) which help DotVVM to reduce the amounts of data transmitted.

* Because the changes in the viewmodel may affect the hierarchy of the controls in the page (like adding rows to a [GridView](~/controls/builtin/GridView)), DotVVM re-builds the entire control tree before the command method is executed. It is also possible to re-render some controls and send the new HTML to the browser. However, you don't need any of these things in many cases, and because DotVVM performs these operations for every command, the commands are slower.

In reasonably-sized pages (one `GridView` with up to 100 rows, forms with ~50 fields), the overhead is not significant. That's why many developers prefer commands as their default choice, and use static commands only on places where the performance of commands would not be sufficient.

See the [commands](commands) chapter for more info.

### Static commands

In contract to the commands, static commands are evaluated on the client-side. They can still invoke methods on the server too, but they need to pass all the information the methods will need, because the viewmodel is not transmitted to the server.

Static commands can perform the following kinds of operations:

* **Make changes to the viewmodel** - e. g. `{staticCommand: MyProperty = true}`. This can be done solely in the browser and doesn't require any communication with the server.

* **Call methods on the server and assign the result to a viewmodel property** - e. g. `{staticCommand: MyProperty = SomeMethodOnTheServer(OtherProperty, ...)}`. The method can be a static method, or an instance method declared in a [static command service](static-command-services).

* **Invoke JavaScript methods** - e. g. `{staticCommand: MyProperty = _js.Invoke<string>("someJsMethod", OtherProperty, ...)}`, see [JS directives](~/pages/concepts/client-side-development/js-directive/overview).

* **Invoke REST API bindings** - e. g. `{staticCommand: _myApi.Delete(CustomerId)}`, see [REST API bindings](rest-api-bindings/overview).

Expression in the static command binding is translated to the JavaScript. If the expression contains a method that is on the server, DotVVM will make a request and call the method. You can pass any arguments to the method, and you can use the result of the method to update some viewmodel properties.

Static commands are much more light-weight - they don't need to transmit the viewmodel to the server, they don't build the control tree, or call the [viewmodel lifecycle events](~/pages/concepts/viewmodels/overview).

The disadvantage of static commands is the fact that you need to pass all the data they need as method arguments, and you get only one result value. If you need to perform multiple actions which need many inputs from the viewmodel, or make complex changes to the viewmodel, it is not comfortable to do with static commands - the binding expressions will be long and difficult to read.

```DOTHTML
<!-- Example of a method which does many things, needs a lot of inputs, and needs to change a lot of things in the viewmodel -->
<dot:Button Click="{staticCommand: var result = WeatherService.GetWeatherAndSaveUserPreferences(Location, DateInterval, DisplaySettings);
                                   Weather = result.Weather;
                                   LastUpdated = result.LastUpdated;
                                   Alerts = result.Alerts;
                                   UserPreferencesDialog.IsDisplayed = false}" />
```

Additionally, there are some missing features in static commands, like [validation](~/pages/concepts/validation/overview), [action filters](~/pages/concepts/viewmodels/filters/overview), and others.

See the [static commands](static-commands) chapter for more info.

## See also

* [Commands](commands)
* [Optimize command performance](optimize-command-performance)
* [Static commands](static-commands)
* [Static command services](static-command-services)
* [JS directives](~/pages/concepts/client-side-development/js-directive/overview)