text:
CompositeTileSourceConfigurationWidget::CompositeTileSourceConfigurationWidget(QWeakPointer<CompositeTileSource> composite,
                                                             QWidget *parent) :
    QWidget(parent),
    ui(new Ui::CompositeTileSourceConfigurationWidget),
    _composite(composite)
{
    ui->setupUi(this);

    this->init();
}

CompositeTileSourceConfigurationWidget::~CompositeTileSourceConfigurationWidget()
{
    delete ui;
}

void CompositeTileSourceConfigurationWidget::setComposite(QWeakPointer<CompositeTileSource> nComposite)
{
    _composite = nComposite;
    this->init();
}

//private slot
void CompositeTileSourceConfigurationWidget::handleCurrentSelectionChanged(QModelIndex current, QModelIndex previous)
{
    Q_UNUSED(previous)
    bool enableGUI = current.isValid();

    this->ui->removeSourceButton->setEnabled(enableGUI);
    this->ui->opacitySlider->setEnabled(enableGUI);

    QSharedPointer<CompositeTileSource> strong = _composite.toStrongRef();
    if (strong.isNull())
        return;

    this->ui->moveDownButton->setEnabled(enableGUI &&  (strong->numSources()-1) > current.row());
    this->ui->moveUpButton->setEnabled(enableGUI && 0 < current.row());

    if (enableGUI)
    {
        qreal opacityFloat = strong->getOpacity(current.row());
        this->ui->opacitySlider->setValue(opacityFloat*100);
    }
}

//private slot
void CompositeTileSourceConfigurationWidget::handleCompositeChange()
{
    QItemSelectionModel * selModel = this->ui->listView->selectionModel();
    QModelIndex index = selModel->currentIndex();

    QSharedPointer<CompositeTileSource> strong = _composite.toStrongRef();
    if (strong.isNull())
        return;

    qreal opacityFloat = strong->getOpacity(index.row());
    this->ui->opacitySlider->setValue(opacityFloat*100);
}

//private slot
void CompositeTileSourceConfigurationWidget::addOSMTileLayer()
{
    QSharedPointer<CompositeTileSource> composite = _composite.toStrongRef();
    if (composite.isNull())
        return;

    QSharedPointer<OSMTileSource> source(new OSMTileSource(OSMTileSource::OSMTiles));
    composite->addSourceTop(source);
}

//private slot
void CompositeTileSourceConfigurationWidget::addMapQuestLayer()
{
    QSharedPointer<CompositeTileSource> composite = _composite.toStrongRef();
    if (composite.isNull())
        return;

    QSharedPointer<OSMTileSource> source(new OSMTileSource(OSMTileSource::MapQuestOSMTiles));
    composite->addSourceTop(source);
}

//private slot
void CompositeTileSourceConfigurationWidget::addMapQuestSatLayer()
{
    QSharedPointer<CompositeTileSource> composite = _composite.toStrongRef();
    if (composite.isNull())
        return;

    QSharedPointer<OSMTileSource> source(new OSMTileSource(OSMTileSource::MapQuestAerialTiles));
    composite->addSourceTop(source);
}

//private slot
void CompositeTileSourceConfigurationWidget::on_removeSourceButton_clicked()
{
    QItemSelectionModel * selModel = this->ui->listView->selectionModel();
    QModelIndex index = selModel->currentIndex();

    QSharedPointer<CompositeTileSource> strong = _composite.toStrongRef();
    if (strong.isNull())
        return;

    strong->removeSource(index.row());

    selModel->clear();
}

//private slot
void CompositeTileSourceConfigurationWidget::on_opacitySlider_valueChanged(int value)
{
    QItemSelectionModel * selModel = this->ui->listView->selectionModel();
    QModelIndex index = selModel->currentIndex();

    if (!index.isValid())
        return;

    QSharedPointer<CompositeTileSource> strong = _composite.toStrongRef();
    if (strong.isNull())
        return;

    qreal opacityFloat = (qreal)value / 100.0;

    strong->setOpacity(index.row(),opacityFloat);
}

//private slot
void CompositeTileSourceConfigurationWidget::on_moveDownButton_clicked()
{
    QItemSelectionModel * selModel = this->ui->listView->selectionModel();
    QModelIndex index = selModel->currentIndex();

    if (!index.isValid())
        return;

    QSharedPointer<CompositeTileSource> strong = _composite.toStrongRef();
    if (strong.isNull())
        return;

    int numberOfLayers = strong->numSources();
    int currentIndex = index.row();
    int desiredIndex = qMin<int>(numberOfLayers-1,currentIndex+1);
    strong->moveSource(currentIndex,desiredIndex);
    selModel->setCurrentIndex(selModel->model()->index(desiredIndex,0),
                              QItemSelectionModel::SelectCurrent);
}

//private slot
void CompositeTileSourceConfigurationWidget::on_moveUpButton_clicked()
{
    QItemSelectionModel * selModel = this->ui->listView->selectionModel();
    QModelIndex index = selModel->currentIndex();

    if (!index.isValid())
        return;

    QSharedPointer<CompositeTileSource> strong = _composite.toStrongRef();
    if (strong.isNull())
        return;

    int currentIndex = index.row();
    int desiredIndex = qMax<int>(0,currentIndex-1);
    strong->moveSource(currentIndex,desiredIndex);
    selModel->setCurrentIndex(selModel->model()->index(desiredIndex,0),
                              QItemSelectionModel::SelectCurrent);
}

//private
void CompositeTileSourceConfigurationWidget::init()
{
    //Create a fancy delegate for custom drawing of our list items
    MapTileSourceDelegate * delegato = new MapTileSourceDelegate(_composite,this);

    //Create the model that watches the CompositeTileSource
    MapTileLayerListModel * model = new MapTileLayerListModel(_composite,this);

    //Set the QListView to watch the model and use the delegate
    QAbstractItemModel * oldModel = this->ui->listView->model();
    QAbstractItemDelegate * oldDelegate = this->ui->listView->itemDelegate();

    this->ui->listView->setModel(model);
    this->ui->listView->setItemDelegate(delegato);

    if (oldModel != 0)
        delete oldModel;
    if (oldDelegate != 0)
        delete oldDelegate;

    QItemSelectionModel * selModel = this->ui->listView->selectionModel();
    connect(selModel,
            SIGNAL(currentChanged(QModelIndex,QModelIndex)),
            this,
            SLOT(handleCurrentSelectionChanged(QModelIndex,QModelIndex)));

    //Build a menu of possible sources for the "add" button
    QMenu * menu = new QMenu(this->ui->addSourceButton);
    menu->addAction("OpenStreetMap Tiles", this, SLOT(addOSMTileLayer()));
    menu->addAction("MapQuest-OSM Tiles", this, SLOT(addMapQuestLayer()));
    menu->addAction("MapQuest Open Aerial Tiles", this, SLOT(addMapQuestSatLayer()));
    this->ui->addSourceButton->setMenu(menu);
}


text:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DDZProj.Core;
using DDZEntity;

namespace DDZProj
{
    public partial class AreaBossPoker : UserControl
    {
        Main _MainForm;
        AreaCtrl _TopArea;
        List<DDZPokerImage> _BossImageList;
        public AreaBossPoker(Main f)
        {
            _MainForm = f;
            _TopArea = f.CurrentGame.GetAreaCtrl(AreaPos.top);

            InitializeComponent();

            Init();
        }

        public List<DDZPokerImage> GetBossPokerImageList()
        {
            return _BossImageList;
        }

        #region 初始化
        void Init()
        {
            int w = _TopArea.Width / 2;
            int h = _TopArea.Height / 2;

            int x = _TopArea.Left - w - SysConfiguration.LeftSpec;
            int y = SysConfiguration.TopSpec;

            this.SetBounds(x, y, w, h);

            _MainForm.Controls.Add(this);

        }
        #endregion

        #region 设置Boss扑克

        public void SetBossPoker(List<Poker> bossList)
        {
            _BossImageList = new List<DDZPokerImage>();
            this.Controls.Clear();
            for (int i = 0; i < bossList.Count; i++)
            {
                Poker p = bossList[i];
                DDZPokerImage pi = _MainForm.CurrentGame.PokerImageList[p.No];
                pi.ShowPoker();
                pi.SetBounds(i * SysConfiguration.PokerWidth, 0, SysConfiguration.PokerWidth, SysConfiguration.PokerHeight);
                pi.BringToFront();
                _BossImageList.Add(pi);
                this.Controls.Add(pi);
            }
        }

        public void MoveToBossArea()
        {
            int i = 0;
            foreach (DDZPokerImage pi in this.Controls)
            {
                AreaCtrl area = _MainForm.CurrentGame.GetBossArea();
                if (area != null)
                {
                    pi.SetBounds(i * SysConfiguration.PokerWidth, 0, SysConfiguration.PokerWidth, SysConfiguration.PokerHeight/2);
                    area.Get3BossPokerControl().Controls.Add(pi);
                    i++;
                }

            }
        }

        #endregion

        #region 重置游戏--BossPoker
        public void ResetArea()
        {
            this.Controls.Clear();

        }
        #endregion
    }
}

redpajama_set_name: RedPajamaGithub


text:
<!DOCTYPE html>

    <link rel="icon" href=img\snake_icon.png>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Blog Post 10.27.2017</title>

    <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

    <link href="vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
    <link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
    <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>

    <link href="css/clean-blog.min.css" rel="stylesheet">

        Snake Shenanigans
        <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="col lapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
            Menu

          </button>

                Home

                About

                  Laboratory

                Blog Posts

                Contact

Abstract Thoughts and Snakey's Journey to Mississippi

Creating an abstract to submit for the Technical Research Exhibition for the 2017 Region 3 Fall Regional Conference

              Posted by
                Nelson Raphael
                October 27th, 2017

One could say its really difficult difficult to summarize your research in 300 words or left.

I have been gone for a while so this week I will definitely be providing two posts to catch up. Also a great opportunity is coming up to present the research project.

During November 3rd-5th I will be traveling to Jackson, Mississippi to help host the 2017 National Society of Black Engineers Region 3 Fall Regional Conference since I am a member of the Region III Regional Executive Board. While there a Technical Research Exhibition will be held where students of the southeastern region of the society can present their research findings. The competition consists of two portions, either the showcase or the preliminary portion. Here are the differences between the two.

The preliminary track gives participants the opportunity to interact with a technical audience to present, discuss, and obtain feedback regarding preliminary findings and is recommended to people that are quite new to poster presentations.

The showcase track is for participants that are presenting work to a larger technical audience, and whose work is ready for, in the process of, or already been published in some format.

I am not sure which one I will undertake, since I have presented my poster once before for the ORS banquet during the prior year. However, I have not had numerous poster presentations. Thankfully they will help me decide based off of my abstract.

            NSBE Region III TRE poster

Abstract Writing

When writing an abstract you want to create a 300 word summary that communicates the experiment's content, what the overall goal would be, your methods for reaching that goal, and results and conclusions of your experimentation.

Since I was in the process of creating the poster and the abstract my mentor had me write 10 sentences to summarize the same things listed above to create the poster.

 However, the abstract is a bit more technical thus it needed less high level explanations for the aforementioned items. Fitting your entire research into 300 words is no small feat though.

 Since the presentation is next week and I have to go out of town I will take a short hiatus and return the following week with results from TRE. Wish me luck.

Placeholder text by
              Nelson R.. Photographs by
              NASA on The Commons.

Copyright © Nelson Raphael


text:
import mangler

config = {
    'log_level': 'DEBUG',
    'server_store': ['tiddlywebplugins.mongodb', {
        'db_config': 'mongodb://localhost:27017/'}],
    'indexer': 'tiddlywebplugins.mongodb',
}


text:
A **Context** is a bundle of variables provided to each operation performed by a node. Nodes need a subset of these variables to tell them which fragment of the scene or image to generate. You can add your own variables to the graph, to control the behaviour of upstream nodes.

Contexts are central to Gaffer's processing of 2D and 3D data in a graph, as well as its deferred evaluation engine. Contexts allow nodes to deal with data in small slices rather than as a whole, and generate exactly what is needed. They are the core of every node operation. Depending on the data being processed, a typical variable inside a Context is responsible for specifying one aspect of the scene or image fragment being generated, such as:

- Frame number
- Scene location
- Image tile
- Image channel

Gaffer automatically manages Contexts during processing. These are silently passed upstream, from node to node as they compute requested data. Certain nodes can also add and modify their own variables, for use in driving graph behaviour.

There is no single interface in Gaffer for manually controlling and inspecting a Context in its entirety, but nodes like NameSwitch, Spreadsheet, and Expression can add Context-dependent behaviour to graphs, and the [Python API](../../WorkingWithThePythonScriptingAPI/index.md) provides methods for creating and inspecting Contexts.

## Nodes and Contexts ##

In order to provide a background for why Contexts are necessary, we should look at what kind of workload a node would be up against without them.

Let's consider a 3D scene. Keeping in mind [how scenes are structured](../../WorkingWithScenes/AnatomyOfAScene/index.md), imagine it is filled with hundreds of thousands of locations. Clearly, not every location can be processed at once. Gaffer needs a way to divide up the work to compute the locations one at a time.

This is where Contexts come in. In Gaffer, at no point does a node operate on the entire scene/image. Contexts break the scene/image down into digestible fragments, so each node only generates the parts that they were told to, while deferring the rest. Each computing thread has its own Context, so multiple threads may be processing different parts of the scene/image in parallel, greatly improving efficiency and performance.

```{eval-rst}
.. figure:: images/illustrationContextsSlices.png
    :scale: 100%
    :alt: A scene file being sliced up by location.

    **Figure A:** Contexts allow a scene file to be processed in slices, one location at a time.
```

## Context flow ##

While scene and image data flows down the graph, Contexts flow upstream.

Computation begins when a node is queried to compute a value for its output plug, by something such as a dispatcher or an editor in the interface. At the start of the computation, whatever made the request creates a Context and sets its variables to specify the target location, set, image tile, channel, etc.

The Context then passes up to any plugs that contribute to the output value. When an input plug on the queried node is connected to a plug on an upstream node, it pulls on that upstream plug to retrieve its value. If necessary, the upstream node may need to compute in turn, to produce the upstream plug's value. This pull-compute reaction occurs up through the graph until all required plug values have been calculated to create an output value for the original queried node.

```{eval-rst}
.. figure:: images/illustrationContextsFlow.png
    :scale: 100%
    :alt: Illustration of Contexts flowing through a network.

    **Figure B:** A visualization of Context and computation flow:
```

A suitable Context is created. The node's output plug is queried. The node begins computation.

The node's in plugs are computed. If connected, they pull on connected input plugs, and pass along the Context.

A chain reaction of plug value pulling and Context passing ensues.

Once the last input plugs in the chain are computed, input plugs begin delivering values to the plugs that pulled on them.

A chain reaction of plug value returning ensues.

The out plug is computed.

Some nodes modify the variables inside the Context before they pass it upstream. One example is a node that simply adds a new variable, like a CollectScenes node, which adds a variable that contains the name of the current root location being added to the scene. Another example would be a node that changes a value, such as the TimeWarp node, which can adjust the frame variable so that the upstream nodes compute for a different part of the frame range.

## Context Variables ##

An individual variable inside a Context is called a **Context Variable**. Within the graph, Context Variables are a means of wielding Contexts to drive values, and can be employed to powerful effect to iterate and optimize results.

All Context Variables reside inside their Contexts, and are assignable. Any Context Variable present in a node's Context during processing can have its value expanded in an Expression node, or string plug with [string substitution syntax](../../Reference/ScriptingReference/StringSubstitutionSyntax/index.md).

There are a handful of special Context Variables that are worth noting, which we will informally refer to here as **built-in** Context Variables.

### Built-in Context Variables ###

Built-in Context Variables are hard-coded variables that scene and image nodes read for specifying scene and image fragments to generate. These are the variables that allow Contexts to specify the smallest part of the scene/image at a time. They are declared and assigned values automatically by the node processes themselves.

For a full list of built-in Context Variables and their purposes, see the [Context Variables reference](../../Reference/ContextVariables/index.md).

For a scene computation, the most common built-in Context Variables present are:

- `frame`
- `scene:path`

For an image computation, the most common Context Variables present are:

- `frame`
- `image:tileOrigin`
- `image:channelName`

> Tip : `frame` and `scene:path` will most likely be the only built-in Context Variables that you explicitly reference in plugs.

When Contexts are passed from plug to plug in a scene network, there are two facts you should remember for `scene:path`:

- **Shader networks:** To improve performance, shader networks do not support the use of `scene:path`, and consequently you cannot use it in string substitutions. As a workaround, you can use a CustomAttributes node to generate an attribute that varies with `scene:path`, and then have the shader network reference that attribute.
- **Globals:** When scene globals are computed, the `scene:path` Context Variable is not present in the Context, as location paths are not relevant.

### Other Context Variables ###

All other Context Variables must be declared and initialized, either in the graph itself or in the Gaffer app that's executing the graph. They can handle all the same value types as plug, such as string, int, float, vector, matrix, etc. These other Context Variables are often used to pass an arbitrary variable value upstream.

A Context Variable created at the root of the graph is referred to as a **global** Context Variable. Global Context Variables are always passed into all Contexts, regardless of which node is being executed. They are declared and initialized in the Variables tab of the Settings window (File > Settings...), and can be overridden in individual networks. For a list of the default global Context Variable names, see [Global Context Variables](../../Reference/ContextVariables/index.html#global-context-variables).

Some nodes create and add Context Variables, such as ContextVariables, Wedge, CollectScenes, and CollectImages nodes. They each have at least one string plug that generates a Context Variable to vary upstream behaviour. For convenience, some of these string plugs have default variable names, but you can provide your own. For a list of the nodes with default node Context Variable names, see [Node default Context Variables](../../Reference/ContextVariables/index.html#node-default-context-variables).

## Contexts in action ##

Let's work through a series of practical examples of wielding Contexts in scene and image networks. Each of these modify the Context to achieve a result, but all demonstrate the same principles: Contexts start at the queried node, and flow up the graph to upstream connected plugs.

### Reading a Context Variable with a string plug ###

```{eval-rst}
.. image:: images/conceptContextsReadingContextVariable.png
    :width: 100%
    :alt: A basic scene network where a string plug substitutes a Context Variable.
```

In this most basic example, a ContextVariables node inserts a `message` string Context Variable into the Context. Then, through string substitution, the upstream Text node reads the variable (`${message}`). When the scene is computed, the geometry displays the value of the variable: `received`.

### Editor focus and Context flow ###

Let's put Context flow into practice, and examine how editor focus can trip you up with regards to Context flow. This is a very common mistake to make when first learning how to wield Contexts.

Let's reuse the above network, which we demonstrated by focusing the editors on the ContextVariables node. As we mentioned earlier, focusing an editor on a node queries it. Let's see what happens when we focus on the Text node, instead.

```{eval-rst}
.. image:: images/conceptContextsEditorFocus.png
    :width: 100%
    :alt: The prior network, but the scene hasn't computed.
```

The editors are focused on it, but no geometry is visible. We can quickly tell that the node in fact did compute, because its location is visible in the Hierarchy View. The Text plug substituted the `message` Context Variable with an empty string, because it didn't exist.

This is because the Text node **cannot** reach downstream to read `message`. Contexts start at the queried node, and then move **up** when computing plugs pull on their inputs. We need the ContextVariables node to compute **before** the Text node, so it can insert `message` into the Context and pass it up. In the interface, the only way to see the result of `message` is to query the ContextVariables node or something downstream of it. Therefore for the purposes of this network, to see the results of a successful substitution of `message`, we need to focus the editors on the ContextVariables node.

### Context Variables in expressions ###

Like any other plug, when an Expression node drives a plug, that plug will pass along its Context during computation. The expression code can then read the values of the Context Variables with Python or OSL. For a full list of methods for accessing Context Variables in Python and OSL, see the [Expressions reference](../../Reference/ScriptingReference/Expressions/index.html#context-variables).

> Important : The Expression node does **not** support creating or modifying Context Variables.

In this network, we drive the vertical translation of a cube primitive with the frame number. The frame will produce a different height result when the provided Context contains a different frame value.

```{eval-rst}
.. image:: images/conceptContextsContextVariablesInExpressions.png
    :width: 100%
    :alt: A basic scene network, where an expression uses a Context Variable to drive a plug.
```

When the node calculates its Transform plug, for the y value of its translation, it queries the Expression node. The Expression node, in turn, calculates the frame number from the Context:

```{eval-rst}
.. image:: images/conceptContextsContextVariablesInExpressionsNodeEditor.png
    :alt: The Expression node's code from the prior network.
```

> Tip : In Python, since accessing Context Variables with dictionary syntax does not allow you to define a fallback value, your expression could cause errors when the Context Variable is not defined, which will usually be the case at most nodes of the graph. We therefore recommend using the `context.get()` method and providing a fallback value, so the method always returns a value.

### Context Variables and the Random node ###

```{eval-rst}
.. image:: images/conceptContextsRandomNode1.png
    :width: 100%
    :alt: A scene with duplicated cubes in a line, without any randomization.
```

In this next example, a cube has been duplicated several times, with each copy translated further to the side. We want to apply a random vertical translation to each cube by adjusting a Transform node. To do this, we must drive the Transform node's plug with a Random node, and the Random node will map a unique value to each of the scene's paths.

```{eval-rst}
.. image:: images/conceptContextsRandomNode2.png
    :width: 100%
    :alt: The same scene, with random height translation.
```

```{eval-rst}
.. image:: images/conceptContextsRandomNode2NodeEditor.png
    :alt: The plugs of the Random node, with the Context Entry referencing `scene:path` to vary the translation per location.
```

Here the Random node drives the _y_-translate of a Transform node filtered to the cubes. Its Context Entry plug targets `scene:path`. Set up this way, the Random node derives a random value between `-1` and `1` from the current path in the Context. From there, this random value is passed to the Transform node, and translates the cube's height.

Since each location's path is unique, the randomized values are based on the `scene:path` Context Variable, and the Transform node is filtered to every location in the scene, we end up with per-location random height on each sphere.

> Important : In order to provide random results that can repeatedly match the set of random values to the locations/tiles in the same order, the Random node's values are derived from its seed in conjunction with a Context Variable in its Context Entry plug.

We should note that for this network to function properly, the connected PathFilter node must filter for every location, so it has a value of `*`.

### Querying results with Contexts ###

```{eval-rst}
.. image:: images/conceptContextsQueryingResults.png
    :width: 100%
    :alt: The same randomly-translated cube graph.
```

In the example above, we created a plug value that varies across Contexts via `scene:path`. As such, you won't be able to see the plug's actual values used during computation. This is because the Node Editor can only display one plug value at a time, and generally does so using the graph's global context. But, it is sometimes essential to know the exact value of a plug given a particular Context.

You can do this with the Python API, by establishing a temporary Context and then querying the plug given a specific value of `scene:path`.

First, let's try querying the _y_-translate value for the Transform node from the previous example in the Python Editor:

```
print( root["Transform"]["transform"]["translate"]["y"].getValue() )
```

```{eval-rst}
.. image:: images/conceptContextsQueryingResultsPythonEditor.png
    :alt: When a Python plug query occurs on its own, the return value is based on the Global context.
```

This simply gives us a height passed by the Random node with a blank location, which none of the cubes actually use. What we need is a statement along the lines of "given the cube at location X, what height is the transform?" In fact, the following code effectively does that, by first creating a Context and then querying the plug in it:

```python
context = Gaffer.Context( root.context() )
context["scene:path"] = IECore.InternedStringVectorData( ["cube2"] )
with context:
    print( root["Transform"]["transform"]["translate"]["y"].getValue() )
```

```{eval-rst}
.. image:: images/conceptContextsQueryingResultsFixedPythonEditor.png
    :alt: When a Python plug query occurs inside of an appropriate Context, the return value matches what occurs in the computed graph.
```

The translate value of the plug matches the cube's height as seen in the Scene Inspector:

```{eval-rst}
.. image:: images/conceptContextsQueryingResultsSceneInspector.png
    :alt: The queried location in the Scene Inspector.
```

Observe that we first established `scene:path`, which uses the `InternedStringVectorData` type, and that the path itself **doesn't** contain a forward slash (/).

### Contexts in parallel branches ###

When two plugs in parallel branches are driven by a shared input plug, their Contexts are not shared with that input plug. During computation, each branch is processed in isolation. Take, for example, the following network:

```{eval-rst}
.. image:: images/conceptContextsInParallelBranches.png
    :width: 100%
    :alt: A network that splits into two branches at the top. Nodes in the separate branches are connected to the same upstream Expression node.
```

```{eval-rst}
.. image:: images/conceptContextsInParallelBranchesNodeEditor.png
    :alt: The expression code drives a plug in each respective node.
```

The Text plug of both branch's Text node is driven by a single Expression node. Despite the expression code making calls to both Context Variables, it only substitutes the one that is present in the Context in the branch that is currently computing. When the left branch is computed, only `apples` is defined, so only it returns its proper string. Conversely, when the right branch is computing, only `oranges` is defined, so you only see its string.

The same principle applies when the branches are split at the bottom. In this next image network, the image is overlaid with author and description text if `versionAuthor` or `versionDescription` Context Variables are defined.

```{eval-rst}
.. image:: images/conceptContextsInParallelBranchesDownstream.png
    :width: 100%
    :alt: A network that splits into two branches at the bottom.
```

```{eval-rst}
.. image:: images/conceptContextsInParallelBranchesDownstreamNodeEditor.png
    :alt: The expression code drives a plug in the main branch, but will be empty if the appropriate Context Variables haven't been assigned.
```

When the ImageWriter_DailyOverlay node on the left is executed, the Context Variables are added to the graph, and Expression node substitutes the text. When the ImageWriter node on the right is executed, the text is empty, because its branch isn't connected to the ContextVariables node.

## See also ##

- [Performance Best Practices](../PerformanceBestPractices/index.html#context-and-expressions)
- [Context Variables reference](../../Reference/ContextVariables/index.md)


text:
// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

'use strict';

var http = require('http');
var sprintf = require('util').format;
var url = require('url');

var assert = require('assert-plus');
var mime = require('mime');
var errors = require('restify-errors');

var httpDate = require('./http_date');
var utils = require('./utils');

///--- Globals

var InternalServerError = errors.InternalServerError;

var Response = http.ServerResponse;

///--- API

/**
 * sets the cache-control header. `type` defaults to _public_,
 * and options currently only takes maxAge.
 * @public
 * @function cache
 * @param    {String} type    value of the header
 * @param    {Object} options an options object
 * @returns  {String}         the value set to the header
 */
Response.prototype.cache = function cache(type, options) {
    if (typeof (type) !== 'string') {
        options = type;
        type = 'public';
    }

    if (options && options.maxAge !== undefined) {
        assert.number(options.maxAge, 'options.maxAge');
        type += ', max-age=' + options.maxAge;
    }

    return (this.header('Cache-Control', type));
};

/**
 * turns off all cache related headers.
 * @public
 * @function noCache
 * @returns  {Object} self, the response object
 */
Response.prototype.noCache = function noCache() {
    // HTTP 1.1
    this.header('Cache-Control', 'no-cache, no-store, must-revalidate');

    // HTTP 1.0
    this.header('Pragma', 'no-cache');

    // Proxies
    this.header('Expires', '0');

    return (this);
};

/**
 * Appends the provided character set to the response's Content-Type.
 * e.g., res.charSet('utf-8');
 * @public
 * @function charSet
 * @param    {String} type char-set value
 * @returns  {Object} self, the response object
 */
Response.prototype.charSet = function charSet(type) {
    assert.string(type, 'charset');

    this._charSet = type;

    return (this);
};

/**
 * the response formatter. formats the response in preparation to send it off.
 * callback only used in async formatters. restify does not ship with any
 * async formatters currently.
 * @public
 * @function format
 * @param    {Object | String} body the response body to format
 * @param    {Function}        cb   callback function
 * @returns  {undefined}
 */
Response.prototype.format = function format(body, cb) {
    var log = this.log;
    var formatter;
    var type = this.contentType || this.getHeader('Content-Type');
    var self = this;

    if (!type) {
        if (this.req.accepts(this.acceptable)) {
            type = this.req.accepts(this.acceptable);
        }

        if (!type) {
            // The importance of a status code outside of the
            // 2xx range probably outweighs that of unable being to
            // format the response body
            if (this.statusCode >= 200 && this.statusCode < 300) {
                this.statusCode = 406;
            }

            return cb(null);
        }
    } else if (type.indexOf(';') !== '-1') {
        type = type.split(';')[0];
    }

    if (!(formatter = this.formatters[type])) {
        if (type.indexOf('/') === -1) {
            type = mime.lookup(type);
        }

        if (this.acceptable.indexOf(type) === -1) {
            type = 'application/octet-stream';
        }

        formatter = this.formatters[type] || this.formatters['*/*'];

        // this is a catastrophic case - should always fall back on octet-stream
        // but if for some reason that's gone, return a 500.
        if (!formatter) {
            log.warn({
                req: self.req
            }, 'no formatter found. Returning 500.');
            this.statusCode = 500;
            return cb(null);
        }
    }

    if (this._charSet) {
        type = type + '; charset=' + this._charSet;
    }

    this.setHeader('Content-Type', type);

    if (body instanceof Error && body.statusCode !== undefined) {
        this.statusCode = body.statusCode;
    }
    return (formatter.call(this, this.req, this, body, cb));
};

/**
 * retrieves a header off the response.
 * @public
 * @function get
 * @param    {Object} name the header name
 * @returns  {String}
 */
Response.prototype.get = function get(name) {
    assert.string(name, 'name');

    return (this.getHeader(name));
};

/**
 * retrieves all headers off the response.
 * @public
 * @function getHeaders
 * @returns  {Object}
 */
Response.prototype.getHeaders = function getHeaders() {
    return (this._headers || {});
};
Response.prototype.headers = Response.prototype.getHeaders;

/**
 * sets headers on the response.
 * @public
 * @function header
 * @param    {String} name  the name of the header
 * @param    {String} value the value of the header
 * @returns  {Object}
 */
Response.prototype.header = function header(name, value) {
    assert.string(name, 'name');

    if (value === undefined) {
        return (this.getHeader(name));
    }

    if (value instanceof Date) {
        value = httpDate(value);
    } else if (arguments.length > 2) {
        // Support res.header('foo', 'bar %s', 'baz');
        var arg = Array.prototype.slice.call(arguments).slice(2);
        value = sprintf(value, arg);
    }

    var current = this.getHeader(name);

    // #779, don't use comma separated values for set-cookie, see
    // http://tools.ietf.org/html/rfc6265#section-3
    if (current && name.toLowerCase() !== 'set-cookie') {
        if (Array.isArray(current)) {
            current.push(value);
            value = current;
        } else {
            value = [current, value];
        }
    }

    this.setHeader(name, value);
    return (value);
};

/**
 * short hand method for:
 *     res.contentType = 'json';
 *     res.send({hello: 'world'});
 * @public
 * @function json
 * @param    {Number} code    http status code
 * @param    {Object} object  value to json.stringify
 * @param    {Object} headers headers to set on the response
 * @returns  {Object}
 */
Response.prototype.json = function json(code, object, headers) {
    if (!/application\/json/.test(this.header('content-type'))) {
        this.setHeader('Content-Type', 'application/json');
    }

    return (this.send(code, object, headers));
};

/**
 * sets the link heaader.
 * @public
 * @function link
 * @param    {String} l   the link key
 * @param    {String} rel the link value
 * @returns  {String}     the header value set to res
 */
Response.prototype.link = function link(l, rel) {
    assert.string(l, 'link');
    assert.string(rel, 'rel');

    var _link = sprintf('<%s>; rel="%s"', l, rel);
    return (this.header('Link', _link));
};

/**
 * sends the response object. convenience method that handles:
 *     writeHead(), write(), end()
 * @public
 * @function send
 * @param    {Number} code                      http status code
 * @param    {Object | Buffer | Error} body     the content to send
 * @param    {Object}                  headers  any add'l headers to set
 * @returns  {Object}                           self, the response object
 */
Response.prototype.send = function send(code, body, headers) {
    var isHead = (this.req.method === 'HEAD');
    var log = this.log;
    var self = this;

    if (code === undefined) {
        this.statusCode = 200;
    } else if (code.constructor.name === 'Number') {
        this.statusCode = code;

        if (body instanceof Error) {
            body.statusCode = this.statusCode;
        }
    } else {
        headers = body;
        body = code;
        code = null;
    }

    headers = headers || {};

    if (log.trace()) {
        var _props = {
            code: self.statusCode,
            headers: headers
        };

        if (body instanceof Error) {
            _props.err = body;
        } else {
            _props.body = body;
        }
        log.trace(_props, 'response::send entered');
    }

    this._body = body;

    function _cb(err, _body) {
        // the problem here is that if the formatter throws an error, we can't
        // actually format the error again, since the formatter already failed.
        // So all we can do is send back a 500 with no body, since we don't
        // know at this point what format to send the error as. Additionally,
        // the current 'after' event is emitted _before_ we send the response,
        // so there's no way to re-emit the error here. TODO: clean up 'after'
        // event emitter so we pick up the error here.
        if (err) {
            self._data = null;
            self.statusCode = 500;
            log.error(err, 'unable to format response');
        } else {
            self._data = _body;
        }
        Object.keys(headers).forEach(function (k) {
            self.setHeader(k, headers[k]);
        });

        self.writeHead(self.statusCode);

        if (self._data && !(isHead || code === 204 || code === 304)) {
            self.write(self._data);
        }

        self.end();

        if (log.trace()) {
            log.trace({res: self}, 'response sent');
        }
    }

    if (body !== undefined) {
        this.format(body, _cb);
    } else {
        _cb(null, null);
    }

    return (this);
};

/**
 * sets a header on the response.
 * @public
 * @function set
 * @param    {String} name name of the header
 * @param    {String} val  value of the header
 * @returns  {Object}      self, the response object
 */
Response.prototype.set = function set(name, val) {
    var self = this;

    if (arguments.length === 2) {
        assert.string(name, 'res.set(name, val) requires name to be a string');
        this.header(name, val);
    } else {
        assert.object(name,
            'res.set(headers) requires headers to be an object');
        Object.keys(name).forEach(function (k) {
            self.set(k, name[k]);
        });
    }

    return (this);
};

/**
 * sets the http status code on the response.
 * @public
 * @function status
 * @param    {Number} code http status code
 * @returns  {Number}     the status code passed in
 */
Response.prototype.status = function status(code) {
    assert.number(code, 'code');

    this.statusCode = code;
    return (code);
};

/**
 * toString() serialization.
 * @public
 * @function toString
 * @returns  {String}
 */
Response.prototype.toString = function toString() {
    var headers = this.getHeaders();
    var headerString = '';
    var str;

    Object.keys(headers).forEach(function (k) {
        headerString += k + ': ' + headers[k] + '\n';
    });
    str = sprintf('HTTP/1.1 %s %s\n%s',
        this.statusCode,
        http.STATUS_CODES[this.statusCode],
        headerString);

    return (str);
};

if (!Response.prototype.hasOwnProperty('_writeHead')) {
    Response.prototype._writeHead = Response.prototype.writeHead;
}

/**
 * pass through to native response.writeHead()
 * @public
 * @function writeHead
 * @emits    header
 * @returns  {undefined}
 */
Response.prototype.writeHead = function restifyWriteHead() {
    this.emit('header');

    if (this.statusCode === 204 || this.statusCode === 304) {
        this.removeHeader('Content-Length');
        this.removeHeader('Content-MD5');
        this.removeHeader('Content-Type');
        this.removeHeader('Content-Encoding');
    }

    this._writeHead.apply(this, arguments);
};

/*
 * redirect is sugar method for redirecting. takes a few different signatures:
 * 1) res.redirect(301, 'www.foo.com', next);
 * 2) res.redirect('www.foo.com', next);
 * 3) res.redirect({...}, next);
 * `next` is mandatory, to complete the response and trigger audit logger.
 * @public
 * @param    {Number | String}   arg1 the status code or url to direct to
 * @param    {String | Function} arg2 the url to redirect to, or `next` fn
 * @param    {Function}          arg3 `next` fn
 * @emits    redirect
 * @function redirect
 * @return   {undefined}
 */
Response.prototype.redirect = function redirect(arg1, arg2, arg3) {

    var self = this;
    var statusCode = 302;
    var finalUri;
    var redirectLocation;
    var next;

    // 1) this is signature 1, where an explicit status code is passed in.
    //    MUST guard against null here, passing null is likely indicative
    //    of an attempt to call res.redirect(null, next);
    //    as a way to do a reload of the current page.
    if (arg1 && !isNaN(arg1)) {
        statusCode = arg1;
        finalUri = arg2;
        next = arg3;
    }

    // 2) this is signaure number 2
    else if (typeof (arg1) === 'string') {
        // otherwise, it's a string, and use it directly
        finalUri = arg1;
        next = arg2;
    }

    // 3) signature number 3, using an options object.
    else if (typeof (arg1) === 'object') {

        // set next, then go to work.
        next = arg2;

        var req = self.req;
        var opt = arg1 || {};
        var currentFullPath = req.href();
        var secure = (opt.hasOwnProperty('secure')) ?
                        opt.secure :
                        req.isSecure();

        // if hostname is passed in, use that as the base,
        // otherwise fall back on current url.
        var parsedUri = url.parse(opt.hostname || currentFullPath, true);

        // create the object we'll use to format for the final uri.
        // this object will eventually get passed to url.format().
        // can't use parsedUri to seed it, as it confuses the url module
        // with some existing parsed state. instead, we'll pick the things
        // we want and use that as a starting point.
        finalUri = {
            port: parsedUri.port,
            hostname: parsedUri.hostname,
            query: parsedUri.query,
            pathname: parsedUri.pathname
        };

        // start building url based on options.
        // first, set protocol.
        finalUri.protocol = (secure === true) ? 'https' : 'http';

        // then set host
        if (opt.hostname) {
            finalUri.hostname = opt.hostname;
        }

        // then set current path after the host
        if (opt.pathname) {
            finalUri.pathname = opt.pathname;
        }

        // then add query params
        if (opt.query) {
            if (opt.overrideQuery === true) {
                finalUri.query = opt.query;
            } else {
                finalUri.query = utils.mergeQs(opt.query, finalUri.query);
            }
        }

        // change status code to 301 permanent if specified
        if (opt.permanent) {
            statusCode = 301;
        }
    }

    // if we're missing a next we should probably throw. if user wanted
    // to redirect but we were unable to do so, we should not continue
    // down the handler stack.
    assert.func(next, 'res.redirect() requires a next param');

    // if we are missing a finalized uri
    // by this point, pass an error to next.
    if (!finalUri) {
        return (next(new InternalServerError('could not construct url')));
    }

    redirectLocation = url.format(finalUri);

    self.emit('redirect', redirectLocation);

    // now we're done constructing url, send the res
    self.send(statusCode, null, {
        location: redirectLocation
    });

    // tell server to stop processing the handler stack.
    return (next(false));
};