Home > Web Technology Made Really Easy > HTTP Made Really Easy
HTTP is the network protocol of the Web. It is both simple and powerful. Knowing HTTP enables you to write Web browsers, Web servers, automatic page downloaders, link-checkers, and other useful tools.
This tutorial explains the simple, English-based structure of HTTP communication, and teaches you the practical details of writing HTTP clients and servers. It assumes you know basic socket programming. HTTP is simple enough for a beginning sockets programmer, so this page might be a good followup to a sockets tutorial. This Sockets FAQ (hint: see "Categorized Questions" section at bottom) focuses on C, but the underlying concepts are language-independent.
Since you're reading this, you probably already use CGI. If not, it makes sense to learn that first.
The whole tutorial is about 15 printed pages long, including examples. The first half explains basic HTTP 1.0, and the second half explains the new requirements and features of HTTP 1.1. This tutorial doesn't cover everything about HTTP; it explains the basic framework, how to comply with the requirements, and where to find out more when you need it. If you plan to use HTTP extensively, you should read the specification as well-- see the end of this document for more details.
Before getting started, understand the following two paragraphs:
<LECTURE>
Writing HTTP or other network programs requires more care than programming for a single machine. Of course, you have to follow standards, or no one will understand you. But even more important is the burden you place on other machines.   Write a really bad network program, and you waste many thousands of people's resources at the same time. Sloppy and malicious network programming forces network standards to be modified, made safer but less efficient. So be careful, respectful, and cooperative, for everyone's sake.
In particular, don't be tempted to write programs that automatically follow Web links (called robots or spiders) before you really know what you're doing. They can be useful, but a badly-written robot is one of the worst kinds of programs on the Web, blindly following a rapidly increasing number of links and quickly draining server resources. If you plan to write anything like a robot, please read more about them. There may already be a working program to do what you want. If you really need to write your own, read these guidelines. Definitely support the current Standard for Robot Exclusion, and stay tuned for further developments.
</LECTURE>
OK, enough of that. Let's get started.
Several related topics are discussed on a "footnotes" page:
HTTP stands for Hypertext Transfer Protocol. It's the network protocol used to deliver virtually all files and other data (collectively called resources) on the World Wide Web, whether they're HTML files, image files, query results, or anything else. Usually, HTTP takes place through TCP/IP sockets (and this tutorial ignores other possibilities).
A browser is an HTTP client because it sends requests to an HTTP server (Web server), which then sends responses back to the client. The standard (and default) port for HTTP servers to listen on is 80, though they can use any port.
HTTP is used to transmit resources, not just files. A resource is some chunk of information that can be identified by a URL (it's the R in URL). The most common kind of resource is a file, but a resource may also be a dynamically-generated query result, the output of a CGI script, a document that is available in several languages, or something else.
While learning HTTP, it may help to think of a resource as similar to a file, but more general. As a practical matter, almost all HTTP resources are currently either files or server-side script output.
Like most network protocols, HTTP uses the client-server model: An HTTP client opens a connection and sends a request message to an HTTP server; the server then returns a response message, usually containing the resource that was requested. After delivering the response, the server closes the connection (making HTTP a stateless protocol, i.e. not maintaining any connection information between transactions).
The format of the request and response messages are similar, and English-oriented. Both kinds of messages consist of:
Put another way, the format of an HTTP message is:
<initial line, different for request vs. response> Header1: value1 Header2: value2 Header3: value3 <optional message body goes here, like file contents or query data; it can be many lines long, or even binary data $&*%@!^$@>
Initial lines and headers should end in CRLF, though you should gracefully handle lines ending in just LF. (More exactly, CR and LF here mean ASCII values 13 and 10, even though some platforms may use different characters.)
The initial line is different for the request than for the response. A request line has three parts, separated by spaces: a method name, the local path of the requested resource, and the version of HTTP being used. A typical request line is:
GET /path/to/file/index.html HTTP/1.0
Notes:
The initial response line, called the status line, also has three parts separated by spaces: the HTTP version, a response status code that gives the result of the request, and an English reason phrase describing the status code. Typical status lines are:
HTTP/1.0 200 OK
or
HTTP/1.0 404 Not Found
Notes:
A complete list of status codes is in the HTTP specification (section 9 for HTTP 1.0, and section 10 for HTTP 1.1).
Header lines provide information about the request or response, or about the object sent in the message body.
The header lines are in the usual text header format, which is: one line per header, of the form "Header-Name: value", ending with CRLF. It's the same format used for email and news postings, defined in RFC 822, section 3. Details about RFC 822 header lines:
Thus, the following two headers are equivalent:
Header1: some-long-value-1a, some-long-value-1b
HEADER1: some-long-value-1a, some-long-value-1b
HTTP 1.0 defines 16 headers, though none are required. HTTP 1.1 defines 46 headers, and one (Host:) is required in requests. For Net-politeness, consider including these headers in your requests:
These headers help webmasters troubleshoot problems. They also reveal information about the user. When you decide which headers to include, you must balance the webmasters' logging needs against your users' needs for privacy.
If you're writing servers, consider including these headers in your responses:
Last-Modified: Fri, 31 Dec 1999 23:59:59 GMT
An HTTP message may have a body of data sent after the header lines. In a response, this is where the requested resource is returned to the client (the most common use of the message body), or perhaps explanatory text if there's an error. In a request, this is where user-entered data or uploaded files are sent to the server.
If an HTTP message includes a body, there are usually header lines in the message that describe the body. In particular,
To retrieve the file at the URL
http://www.somehost.com/path/file.html
first open a socket to the host www.somehost.com, port 80 (use the default port of 80 because none is specified in the URL). Then, send something like the following through the socket:
GET /path/file.html HTTP/1.0 From<EMAIL_ADDRESS>User-Agent: HTTPTool/1.0 [blank line here]
The server should respond with something like the following, sent back through the same socket:
After sending the response, the server closes the socket.HTTP/1.0 200 OK Date: Fri, 31 Dec 1999 23:59:59 GMT Content-Type: text/html Content-Length: 1354
Happy New Millennium!
 (more file contents) . . .
To familiarize yourself with requests and responses, manually experiment with HTTP using telnet.
Besides GET, the two most commonly used methods are HEAD and POST.
A HEAD request is just like a GET request, except it asks the server to return the response headers only, and not the actual resource (i.e. no message body). This is useful to check characteristics of a resource without actually downloading it, thus saving bandwidth. Use HEAD when you don't actually need a file's contents.
The response to a HEAD request must never contain a message body, just the status line and headers.
A POST request is used to send data to the server to be processed in some way, like by a CGI script. A POST request is different from a GET request in the following ways:
The most common use of POST, by far, is to submit HTML form data to CGI scripts. In this case, the Content-Type: header is usually application/x-www-form-urlencoded, and the Content-Length: header gives the length of the URL-encoded form data (here's a note on URL-encoding). The CGI script receives the message body through STDIN, and decodes it. Here's a typical form submission, using POST:
POST /path/script.cgi HTTP/1.0 From<EMAIL_ADDRESS>User-Agent: HTTPTool/1.0 Content-Type: application/x-www-form-urlencoded Content-Length: 32 home=Cosby&favorite+flavor=flies
You can use a POST request to send whatever data you want, not just form submissions. Just make sure the sender and the receiving program agree on the format.
The GET method can also be used to submit forms. The form data is URL-encoded and appended to the request URI. Here are more details.
If you're writing HTTP servers that support CGI scripts, you should read the NCSA's CGI definition if you haven't already, especially which environment variables you need to pass to the scripts.
An HTTP proxy is a program that acts as an intermediary between a client and a server. It receives requests from clients, and forwards those requests to the intended servers. The responses pass back through it in the same way. Thus, a proxy has functions of both a client and a server.
Proxies are commonly used in firewalls, for LAN-wide caches, or in other situations. If you're writing proxies, read the HTTP specification; it contains details about proxies not covered in this tutorial.
When a client uses a proxy, it typically sends all requests to that proxy, instead of to the servers in the URLs. Requests to a proxy differ from normal requests in one way: in the first line, they use the complete URL of the resource being requested, instead of just the path. For example,
GET http://www.somehost.com/path/file.html HTTP/1.0
That way, the proxy knows which server to forward the request to (though the proxy itself may use another proxy).
As the saying goes (in network programming, anyway), "Be strict in what you send and tolerant in what you receive." Other clients and servers you interact with may have minor flaws in their messages, but you should try to work gracefully with them. In particular, the HTTP specification suggests the following:
The specification has other suggestions too, like how to handle varying date formats. If your program interprets dates from other programs, read the "Tolerant Applications" section of the specification.
That's the basic structure of HTTP. If you understand everything so far,
you have a good overview of HTTP communication, and should be able to write
simple HTTP 1.0 programs. See this
example to get started.
Again, before you do anything heavy-duty, read
the specification.
The rest of this document tells how to upgrade your clients and servers
to use HTTP 1.1. There is a list of new client requirements, and a
list of new server requirements. You can stop here if HTTP 1.0
satisfies your current needs (though you'll probably need HTTP 1.1 in
the future).
Note: As of early 1997, the Web is moving from HTTP 1.0 to
HTTP 1.1. Whenever practical, use HTTP 1.1. It's more efficient
overall, and by using it, you'll help the Web perform better for everyone.
Like many protocols, HTTP is constantly evolving. HTTP 1.1 has
recently been defined, to address new needs and overcome shortcomings
of HTTP 1.0. Generally speaking, it is a superset of HTTP 1.0.
Improvements include:
HTTP 1.1 requires a few extra things from both clients and servers.
The next two sections detail how to make clients
and servers comply with HTTP 1.1. If
you're only writing clients, you can skip the section on servers. If you're
writing servers, read both sections.
Only requirements for HTTP 1.1 compliance are described here.
HTTP 1.1 has many optional features you may find useful; read
the specification to learn more.
To comply with HTTP 1.1, clients must
Starting with HTTP 1.1, one server at one IP address can be
multi-homed, i.e. the home of several Web domains. For example,
"www.host1.com" and "www.host2.com" can live on the same server.
Several domains living on the same server is like several people
sharing one phone: a caller knows who they're calling for, but whoever
answers the phone doesn't. Thus, every HTTP request must specify which
host name (and possibly port) the request is intended for, with the
Host: header. A complete HTTP 1.1 request might be
Host: is the only required header in an HTTP 1.1 request.
It's also the most urgently needed new feature in HTTP 1.1. Without it,
each host name requires a unique IP address, and we're
quickly running out of IP addresses with the explosion of new domains.
If a server wants to start sending a response before knowing its total
length (like with long script output), it might use the simple
chunked transfer-encoding, which breaks the complete response into
smaller chunks and sends them in series. You can identify such a response
because it contains the "Transfer-Encoding: chunked" header.
All HTTP 1.1 clients must be able to receive chunked messages.
A chunked message body contains a series of chunks, followed by a
line with "0" (zero), followed by optional footers (just like headers), and a
blank line. Each chunk consists of two parts:
So a chunked response might look like the following:
Note the blank line after the last footer. The length of the
text data is 42 bytes (1a + 10, in hex), and the data itself is
abcdefghijklmnopqrstuvwxyz1234567890abcdef. The footers should be
treated like headers, as if they were at the top of the response.
The chunks can contain any binary data, and may be much larger than the
examples here. The size-line parameters are rarely used, but you
should at least ignore them correctly. Footers are also rare, but might
be appropriate for things like checksums or digital signatures.
For comparison, here's the equivalent to the above response, without
using chunked encoding:
In HTTP 1.0 and before, TCP connections are closed after each request
and response, so each resource to be retrieved requires its own connection.
Opening and closing TCP connections takes a substantial amount of CPU time,
bandwidth, and memory. In practice, most Web pages consist of several
files on the same server, so much can be saved by allowing several requests
and responses to be sent through a single persistent connection.
Persistent connections are the default in HTTP 1.1, so nothing special
is required to use them. Just open a connection and send several requests
in series (called pipelining), and read the responses in the same
order as the requests were sent. If you do this, be very careful to read
the correct length of each response, to separate them correctly.
If a client includes the "Connection: close" header
in the request, then the connection will be closed after the corresponding
response. Use this if you don't support persistent connections,
or if you know a request will be the last on its connection. Similarly,
if a response contains this header, then the server will close the
connection following that response, and the client shouldn't send any
more requests through that connection.
A server might close the connection before all responses are sent, so
a client must keep track of requests and resend them as needed. When
resending, don't pipeline the requests until you know the connection is
persistent. Don't pipeline at all if you know the server won't support
persistent connections (like if it uses HTTP 1.0, based on a previous
response).
During the course of an HTTP 1.1 client sending a request to a server,
the server might respond with an interim "100 Continue"
response. This means the server has received the first part of the request,
and can be used to aid communication over slow links. In any case, all
HTTP 1.1 clients must handle the 100 response correctly (perhaps
by just ignoring it).
The "100 Continue" response is structured like
any HTTP response, i.e. consists of a status line, optional headers,
and a blank line. Unlike other responses, it is always followed by
another complete, final response.
So, further extending the last example, the full data that comes
back from the server might consist of two responses in series, like
To handle this, a simple HTTP 1.1 client might read one response from the
socket; if the status code is 100, discard the first response and read the
next one instead.
To comply with HTTP 1.1, servers must:
Because of the urgency of implementing the new Host:
header, servers are not allowed to tolerate HTTP 1.1 requests without it.
If a server receives such a request, it must return a
"400 Bad Request" response, like
This requirement applies only to clients using HTTP 1.1, not
any future version of HTTP.
If the request uses an HTTP version later than 1.1, the server can
accept an absolute URL instead of a Host: header (see
next section).
If the request uses HTTP 1.0, the server may accept the request without
any host identification.
The Host: header is actually an interim solution to
the problem of host identification. In future versions of HTTP,
requests will use an absolute URL instead of a pathname, like
To enable this protocol transition, HTTP 1.1 servers must accept this
form of request, even though HTTP 1.1 clients won't send them. The server
must still report an error if an HTTP 1.1 client leaves out
the Host: header, as described in the
previous section.
Just as HTTP 1.1 clients must accept chunked responses, servers must
accept chunked requests (an unlikely scenario, but possible). See the
earlier section on
HTTP 1.1 Clients
for details of the chunked data format.
Servers aren't required to generate chunked messages; they just have to
be able to receive them.
If an HTTP 1.1 client sends multiple requests through a single connection,
the server should send responses back in the same order as the requests--
this is all it takes for a server to support persistent connections.
If a request includes the "Connection: close" header,
that request is the final one for the connection and the server should
close the connection after sending the response. Also, the server should
close an idle connection after some timeout period (can be anything;
10 seconds is fine).
If you don't want to support persistent connections, include the
"Connection: close" header in the response. Use this
header whenever you want to close the connection, even if not all requests
have been fulfilled. The header says that the connection will be closed
after the current response, and a valid HTTP 1.1 client will handle it
correctly.
As described in the section on
HTTP 1.1 Clients,
this response exists to help deal with slow links.
When an HTTP 1.1 server receives the first line of an HTTP 1.1
(or later) request, it must respond with either
"100 Continue" or an error. If it sends the
"100 Continue" response, it must also send another,
final response, once the request has been processed. The
"100 Continue" response requires no headers, but must
be followed by the usual blank line, like:
Don't send "100 Continue" to HTTP 1.0 clients,
since they don't know how to handle it.
Caching is an important improvement in HTTP 1.1, and can't work
without timestamped responses. So, servers must timestamp every response
with a Date: header containing the current time, in the form
All responses except those with 100-level status (but including error
responses) must include the Date: header.
All time values in HTTP use Greenwich Mean Time.
To avoid sending resources that don't need to be sent, thus saving
bandwidth, HTTP 1.1 defines the If-Modified-Since: and
If-Unmodified-Since: request headers.
The former says "only send the resource if it has changed since this date";
the latter says the opposite. Clients aren't required to use them, but
HTTP 1.1 servers are required to honor requests that do use them.
Unfortunately, due to earlier HTTP versions,
the date value may be in any of three possible formats:
Again, all time values in HTTP use Greenwich Mean Time (though try to be
tolerant of non-GMT times). If a date with a two-digit year seems to be more
than 50 years in the future, treat it as being in the past-- this
helps with the millennium bug. In fact, do this with any date handling in
HTTP 1.1.
Although servers must accept all three date formats, HTTP 1.1
clients and servers must only generate the first kind.
If the date in either of these headers is invalid, or is in the future,
ignore the header.
If, without the header, the request would result in an unsuccessful
(non-200-level) status code, ignore the header and send the non-200-level
response. In other words, only apply these headers when you know the
resource would otherwise be sent.
The If-Modified-Since: header is used with a GET
request. If the requested resource has been modified since the given date,
ignore the header and return the resource as you normally would.
Otherwise, return a "304 Not Modified" response,
including the Date: header and no message body, like
The If-Unmodified-Since: header is similar, but can be
used with any method. If the requested resource has not been
modified since the given date, ignore the header and return the resource as
you normally would. Otherwise, return a
"412 Precondition Failed" response, like
To comply with HTTP 1.1, a server must support at least the GET and HEAD
methods. If you're handling CGI scripts, you should probably support the
POST method too.
Four other methods (PUT, DELETE, OPTIONS, and TRACE) are defined in
HTTP 1.1, but are rarely used. If a client requests a method you don't
support, respond with "501 Not Implemented", like
To be compatible with older browsers, HTTP 1.1 servers must support
HTTP 1.0 requests. In particular, when a request uses HTTP 1.0
(as identified in the initial request line),
If you plan to do anything elaborate in HTTP, read the
official specification. HTTP 1.0 was never made an official
Internet standard, but the de facto standard is described in
RFC 1945.
HTTP 1.1 was developed by a
working group of the
IETF, openly gathering input from many
sources before reaching an approximate consensus. The resulting specification
is RFC 2616,
released in June 1999.
These documents are available in various formats:
Download and print the version you'll be using, for reference and
bedtime reading.
The World Wide Web Consortium
has a
page devoted to HTTP
including news and updates, and a page listing
HTTP specifications,
drafts, and reports.
Other RFC's you might find useful:
Conclusion
HTTP 1.1
HTTP 1.1 Clients
Host: Header
except the ":80" isn't required, since that's the default HTTP port.
GET /path/file.html HTTP/1.1
Host: www.host1.com:80
[blank line here]
Chunked Transfer-Encoding
HTTP/1.1 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/plain
Transfer-Encoding: chunked
1a; ignore-stuff-here
abcdefghijklmnopqrstuvwxyz
10
1234567890abcdef
0
some-footer: some-value
another-footer: another-value
[blank line here]
HTTP/1.1 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/plain
Content-Length: 42
some-footer: some-value
another-footer: another-value
abcdefghijklmnopqrstuvwxyz1234567890abcdef
Persistent Connections and the "Connection: close" Header
The "100 Continue" Response
HTTP/1.1 100 Continue
HTTP/1.1 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Content-Type: text/plain
Content-Length: 42
some-footer: some-value
another-footer: another-value
abcdefghijklmnoprstuvwxyz1234567890abcdef
HTTP 1.1 Servers
Requiring the Host: Header
HTTP/1.1 400 Bad Request
Content-Type: text/html
Content-Length: 111

No Host: header received

HTTP 1.1 requests must include the Host: header.

Accepting Absolute URL's
GET http://www.somehost.com/path/file.html HTTP/1.2
Chunked Transfer-Encoding
Persistent Connections and the "Connection: close" Header
Using the "100 Continue" Response
HTTP/1.1 100 Continue
[blank line here]
[another HTTP response will go here]
The Date: Header
Date: Fri, 31 Dec 1999 23:59:59 GMT
Handling Requests with If-Modified-Since: or If-Unmodified-Since:
Headers
If-Modified-Since: Fri, 31 Dec 1999 23:59:59 GMT
If-Modified-Since: Friday, 31-Dec-99 23:59:59 GMT
If-Modified-Since: Fri Dec 31 23:59:59 1999
HTTP/1.1 304 Not Modified
Date: Fri, 31 Dec 1999 23:59:59 GMT
[blank line here]
HTTP/1.1 412 Precondition Failed
[blank line here]
Supporting the GET and HEAD methods
HTTP/1.1 501 Not Implemented
[blank line here]
Supporting HTTP 1.0 Requests
The HTTP Specification
© 1997
James Marshall
(comments welcome)
| Last (significantly) modified: August 15, 1997 | http://www.jmarshall.com/easy/http/ |


Multi-host networking with standalone swarms
Estimated reading time: 12 minutesStandalone swarm only!
This article only applies to users who need to use a standalone swarm with Docker, as opposed to swarm mode. Standalone swarms (sometimes known as Swarm Classic) rely on an external key-value store to store networking information. Docker swarm mode stores networking information in the Raft logs on the swarm managers. If you use swarm mode, see swarm mode networking instead of this article.
Users of Universal Control Plane do use an external key-value store, but UCP manages it for you, and you do not need to manually intervene. If you run into issues with the key-value store, see Troubleshoot the etcd key-value store
If you are using standalone swarms and not using UCP, this article may be useful
to you. This article uses an example to explain the basics of creating a
multi-host network using a standalone swarm and the overlay
network driver.
Unlike bridge
networks, overlay networks require some pre-existing conditions
before you can create one:
Overlay networking with an external key-value store
To use Docker with an external key-value store, you need the following:
- Access to the key-value store. Docker supports Consul, Etcd, and ZooKeeper (Distributed store) key-value stores. This example uses Consul.
- A cluster of hosts with connectivity to the key-value store.
- Docker running on each host in the cluster.
- Hosts within the cluster must have unique hostnames because the key-value store uses the hostnames to identify cluster members.
Docker Machine and Docker Swarm are not mandatory to experience Docker multi-host networking with a key-value store. However, this example uses them to illustrate how they are integrated. You use Machine to create both the key-value store server and the host cluster using a standalone swarm.
Note: These examples are not relevant to Docker running in swarm mode and do not work in such a configuration.
Prerequisites
Before you begin, make sure you have a system on your network with the latest version of Docker and Docker Machine installed. The example also relies on VirtualBox. If you installed on a Mac or Windows with Docker Toolbox, you have all of these installed already.
If you have not already done so, make sure you upgrade Docker and Docker Machine to the latest versions.
Set up a key-value store
An overlay network requires a key-value store. The key-value store holds information about the network state which includes discovery, networks, endpoints, IP addresses, and more. Docker supports Consul, Etcd, and ZooKeeper key-value stores. This example uses Consul.
-
Log into a system prepared with Docker and Docker Machine installed.
-
Provision a VirtualBox machine called
mh-keystore
.$ docker-machine create -d virtualbox mh-keystore
When you provision a new machine, the process adds Docker to the host. This means rather than installing Consul manually, you can create an instance using the consul image from Docker Hub. You do this in the next step.
-
Set your local environment to the
mh-keystore
machine.$ eval "$(docker-machine env mh-keystore)"
-
Start a
consul
container running on themh-keystore
Docker machine.$ docker run -d \ --name consul \ -p "8500:8500" \ -h "consul" \ consul agent -server -bootstrap -client "<IP_ADDRESS>"
The client starts a
consul
image running in themh-keystore
Docker machine. The server is calledconsul
and is listening on port8500
. -
Run the
docker ps
command to see theconsul
container.$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a47492d6c4d1 consul "docker-entrypoint..." 2 seconds ago Up 1 second 8300-8302/tcp, 8301-8302/udp, 8600/tcp, 8600/udp, <IP_ADDRESS>:8500->8500/tcp consul
Keep your terminal open and move on to Create a swarm cluster.
Create a swarm cluster
In this step, you use docker-machine
to provision the hosts for your network.
You don’t actually create the network yet. You create several
Docker machines in VirtualBox. One of the machines acts as the swarm manager
and you create that first. As you create each host, you pass the Docker
daemon on that machine options that are needed by the overlay
network driver.
Note: This creates a standalone swarm cluster, rather than using Docker in swarm mode. These examples are not relevant to Docker running in swarm mode and do not work in such a configuration.
 This option tells the Engine the location of the key-value store for theoverlay
network. The bash expansion$(docker-machine ip mh-keystore)
resolves to the IP address of the Consul server you created in “STEP 1”. The--cluster-advertise
option advertises the machine on the network. -
Create another host and add it to the swarm.
$ docker-machine create -d virtualbox \ --swarm \ --swarm-discovery="consul://$(docker-machine ip mh-keystore):8500" \ --engine-opt="cluster-store=consul://$(docker-machine ip mh-keystore):8500" \ --engine-opt="cluster-advertise=eth1:2376" \ mhs-demo1
-
List your Docker machines to confirm they are all up and running.
$ docker-machine ls NAME ACTIVE DRIVER STATE URL SWARM default - virtualbox Running tcp://<IP_ADDRESS>:2376 mh-keystore * virtualbox Running tcp://<IP_ADDRESS>:2376 mhs-demo0 - virtualbox Running tcp://<IP_ADDRESS>:2376 mhs-demo0 (master) mhs-demo1 - virtualbox Running tcp://<IP_ADDRESS>:2376 mhs-demo0
At this point you have a set of hosts running on your network.
Leave your terminal open and go on to Create the overlay network.
Create the overlay network
To create an overlay network:
-
Set your docker environment to the swarm manager.
$ eval $(docker-machine env --swarm mhs-demo0)
Using the
--swarm
flag withdocker-machine
restricts thedocker
commands to swarm information alone. -
Use the
docker info
command to view the swarm.$ docker info Containers: 3 Images: 2 Role: primary Strategy: spread Filters: affinity, health, constraint, port, dependency Nodes: 2 mhs-demo0: <IP_ADDRESS>:2376 └ Containers: 2 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 1.021 GiB └ Labels: executiondriver=native-0.2, kernelversion=4.1.10-boot2docker, operatingsystem=Boot2Docker 1.9.0 (TCL 6.4); master : 4187d2c - Wed Oct 14 14:00:28 UTC 2015, provider=virtualbox, storagedriver=aufs mhs-demo1: <IP_ADDRESS>:2376 └ Containers: 1 └ Reserved CPUs: 0 / 1 └ Reserved Memory: 0 B / 1.021 GiB └ Labels: executiondriver=native-0.2, kernelversion=4.1.10-boot2docker, operatingsystem=Boot2Docker 1.9.0 (TCL 6.4); master : 4187d2c - Wed Oct 14 14:00:28 UTC 2015, provider=virtualbox, storagedriver=aufs CPUs: 2 Total Memory: 2.043 GiB Name: 30438ece0915
This output shows that you are running three containers and two images on the manager.
-
Create your
overlay
network.$ docker network create --driver overlay --subnet=<IP_ADDRESS>/24 my-net
You only need to create the network on a single host in the cluster. In this case, you used the swarm manager but you could easily have run it on any host in the swarm.
Note: It is highly recommended to use the
--subnet
option when creating a network. If the--subnet
is not specified, Docker automatically chooses and assigns a subnet for the network and it could overlap with another subnet in your infrastructure that is not managed by Docker. Such overlaps can cause connectivity issues or failures when containers are connected to that network. -
Check that the network exists:
$ docker network ls NETWORK ID NAME DRIVER 412c2496d0eb mhs-demo1/host host dd51763e6dd2 mhs-demo0/bridge bridge 6b07d0be843f my-net overlay b4234109bd9b mhs-demo0/none null 1aeead6dd890 mhs-demo0/host host d0bb78cbe7bd mhs-demo1/bridge bridge 1c0eb8f69ebb mhs-demo1/none null
Since you are in the swarm manager environment, you see all the networks on all the swarm participants: the default networks on each Docker daemon and the single overlay network. Each network has a unique ID and a namespaced name.
-
Switch to each swarm agent in turn and list the networks.
$ eval $(docker-machine env mhs-demo0) $ docker network ls NETWORK ID NAME DRIVER 6b07d0be843f my-net overlay dd51763e6dd2 bridge bridge b4234109bd9b none null 1aeead6dd890 host host $ eval $(docker-machine env mhs-demo1) $ docker network ls NETWORK ID NAME DRIVER d0bb78cbe7bd bridge bridge 1c0eb8f69ebb none null 412c2496d0eb host host 6b07d0be843f my-net overlay
Both agents report they have the my-net
network with the 6b07d0be843f
ID.
You now have a multi-host container network running!
Run an application on your network
Once your network is created, you can start a container on any of the hosts and it automatically is part of the network.
-
Set your environment to the swarm manager.
$ eval $(docker-machine env --swarm mhs-demo0)
-
Start an Nginx web server on the
mhs-demo0
instance.$ docker run -itd \ --name=web \ --network=my-net \ --env="constraint:node==mhs-demo0" \ nginx:alpine
-
Run a
busybox
instance on themhs-demo1
instance and get the contents of the Nginx server’s home page.$ docker run -it --rm \ --network=my-net \ --env="constraint:node==mhs-demo1" \ busybox wget -O- http://web Unable to find image 'busybox:latest' locally latest: Pulling from library/busybox ab2b8a86ca6c: Pull complete 2c5ac3f849df: Pull complete Digest: sha256:5551dbdfc48d66734d0f01cafee0952cb6e8eeecd1e2492240bf2fd9640c2279 Status: Downloaded newer image for busybox:latest Connecting to web (<IP_ADDRESS>:80) <!DOCTYPE html>   <title>Welcome to nginx!</title>
Welcome to nginx!

If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

For online documentation and support, refer to nginx.org.
 Commercial support is available at nginx.com.

Thank you for using nginx.
   - 100% |*******************************| 612 0:00:00 ETA
Check external connectivity
As you’ve seen, Docker’s built-in overlay network driver provides out-of-the-box
connectivity between the containers on multiple hosts within the same network.
Additionally, containers connected to the multi-host network are automatically
connected to the docker_gwbridge
network. This network allows the containers
to have external connectivity outside of their cluster.
-
Change your environment to the swarm agent.
$ eval $(docker-machine env mhs-demo1)
-
View the
docker_gwbridge
network, by listing the networks.$ docker network ls NETWORK ID NAME DRIVER 6b07d0be843f my-net overlay dd51763e6dd2 bridge bridge b4234109bd9b none null 1aeead6dd890 host host e1dbd5dff8be docker_gwbridge bridge
-
Repeat steps 1 and 2 on the swarm manager.
$ eval $(docker-machine env mhs-demo0) $ docker network ls NETWORK ID NAME DRIVER 6b07d0be843f my-net overlay d0bb78cbe7bd bridge bridge 1c0eb8f69ebb none null 412c2496d0eb host host 97102a22e8d2 docker_gwbridge bridge
-
Check the Nginx container’s network interfaces.
$ docker container exec web ip addr 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet <IP_ADDRESS>/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 22: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default link/ether 02:42:0a:00:09:03 brd ff:ff:ff:ff:ff:ff inet <IP_ADDRESS>/24 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:aff:fe00:903/64 scope link valid_lft forever preferred_lft forever 24: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff inet <IP_ADDRESS>/16 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe12:2/64 scope link valid_lft forever preferred_lft forever
The eth0
interface represents the container interface that is connected to
the my-net
overlay network. While the eth1
interface represents the
container interface that is connected to the docker_gwbridge
network.
Use Docker Compose with swarm classic
Refer to the Networking feature introduced in Compose V2 format and execute the multi-host networking scenario in the swarm cluster used above.


PerformInteraction Response is sent, when SDLPerformInteraction has been called
@since SDL 1.0
ID of the choice that was selected in response to PerformInteraction. Only is valid if general result is “success:true”.
Optional, Integer, 0 - 2,000,000,000
@property (nonatomic, strong, nullable) NSNumber<SDLInt> *choiceID;
var choiceID: (NSNumber & SDLInt)? { get set }
Manually entered text selection, e.g. through keyboard. Can be returned in lieu of choiceID, depending on the trigger source.
Optional, Max length 500 chars
@property (nonatomic, strong, nullable) NSString *manualTextEntry;
var manualTextEntry: String? { get set }
A SDLTriggerSource object which will be shown in the HMI. Only is valid if resultCode is SUCCESS.
@property (nonatomic, strong, nullable) SDLTriggerSource triggerSource;
var triggerSource: SDLTriggerSource? { get set }


| DOSE: T+ 0:00 |
15 mg |
oral |
2C-E |
(powder / crystals) |
| T+ 0:15 |
4 hits |
smoked |
Cannabis |
(plant material) |
The evening started with 15mg of 2C-E added to a fair quantity of water. Had just started reading PiHKAL and remembered Shulgin's mention of 'if you're looking for a good time, you'll get a good time. If you're looking for something profound, you'll get something profound'
Well I decided I was looking for something profound that evening. Perhaps my mistake.
t+0:15 - I was invited by a friend to take a few hits of cannabis with him and his girlfriend. I remember reading reports of enhanced effects with cannabis, so I thought I'd try it out. After all, I was looking for something profound. I have not eaten for about 6 hours.
t+0:25 - I am forced to pass the pipe after several hits, because I begin to fear this was a mistake. Light headedness starting to set in slowly, and I continually glance at my hands to check the progress of the 2C-E. (I've found I can identify various stages through the morphing of the skin on my palm)
t+0:35 - I lay on my friends bed as trails start appearing. I glance at my hand and am unable to focus very clearly on it. I watch as my friend and his girlfriend touch eachother, in what at least appears to me as quite intimately. They're whispering, and it sounds like she's asking about me, and comments on how I am shaking. My friend tries to explain what it's like to hallucinate, by comparing movement to dancing in a strobe light.
t+0:40 - I fear that things are setting on far faster and far more intense than I can handle. I pull out my sunglasses to help mellow the visualizations and trails. It also dims the room. (I've found that most of the time, sunglasses help to calm myself if things seem too fast) I notice my two friends move about in the familiar fast-forward motion that I am accustomed to with 2C-E. They decide to put in the movie 'Freaks and Geeks'.
t+0:45 - The sun glasses aren't helping much. They seem to be fogging up, although I know they're not. I remove them and everything becomes clear again.
t+0:47 - The movie is very interesting. I'm sure I've seen it before, but everything keeps changing. I find myself IN the movie; as if the actors are right next to me and talking to me. The movie continually changes plots and goes from a high school setting, to a hospital, then to a porn set. It reminds me of another movie...
t+0:50 - The movie is scaring me. I don't know what's going on with it, and find it extremely hard to concentrate on it. I continually close my eyes tightly and find myself out of the movie, back on the bed. If I watch, I'm drawn into it again.
t+0:52 - I decide I can't watch the movie, so I look around the room. The curtains suddenly expand and surround the entire room, covering the walls in horizontal lines. Everything else seems blurred, as If i'm look through some sort of distorted glass or crystal.
t+0:55 - The room feels small. The shifting curtains which have surrounded the room feel as if they're moving in. I tell my friends I need to go outside, and they thank me for joining them and I exit the room. I take the elevator down to the ground and step outside.
t+0:56 - The cold air seems to help bring me back to reality, but only for a short while. I don't remember if I packed a bowl of tobacco or not. I think so.
--Time starts getting confusing, hence the ~, signifying my guess. --
~t+1:00 - I don't smoke for long. Its strange outside. I try the sunglasses again, making me appear fully out of place, but they still seem foggy. Now things start getting freaky. I see two girls walking a dog, they pass me, but only get about 30 feet before they stop. They stop in mid stride, the dog absolutely still. I look away, and look back - they're still there, frozen. I look away again, and see a car ahead. It too appears frozen. It could have been the traffic light, but I swear the car is completely still. I hear the sounds of the city around me, but nothing is moving. I decide to take a walk.
~t+1:05 - The walk helps. I start moving, and so does everything else. I quickly pass the girls and dog. I do not remember how far I went, but at some point I just turned around and started walking back the same way I came.
~t+1:07 - I have to pass this long metal-picket fence about a block before I get back, but it's like every step I take, sets me back two steps. It's as if I'm moving backwards while walking forwards... Looking at the fence does not help, so I concentrate my vision, which is bright and clear at this point, on building far behind it. I can now walk forward.
~t+1:10 - I lean up against a giant planter just outside the doors, as I regularly do. I look through the double doors, and notice someone talking to the security guy at the front. I look away for a moment, and look back in: He's gone. Again I move my attention to something else, and once again look in - now he's there again. This continues several times, with me occasionally squinting hard so that I may 'bring myself back to reality'. Each time I do, the person appears. If I drift away, he's gone again. Throughout this, I am looking at my watch occasionally, which I quickly find does not help at all. I look at it once, and it says 11:48, I look again, and it says 12:32, again and it says 10:28. At this point, I'm worried. I think that maybe I'm really not outside right now, and that I'm still upstairs in my friends bed. I close my eyes tight and imagine myself lying back in bed; I almost collapse, but it's as if I was really coming back to true reality, upstairs in my friend's bed.
~t+1:20 - I'm getting worried. Between the watch, and the disappearing person, and frozen objects, I fumble for my phone and try to call my friend back up in his room, in hopes that he'll come out and talk with me for a while. I find his number and call it. It rings and rings... I get his voicemail. It's like a horror movie now. I'm getting more anxious and scared. I try the number several times. No answer.
~t+1:25 - It seems like i've been outside forever. I keep telling myself that I haven't, but that I'm really outside. For some reason I ignore myself, and my mind keeps telling me that I'm still upstairs, in bed. I call another friend. No answer. I try the number again, and finally get in contact with someone. It feels as if I haven't talked to anyone in years... I'm happy to hear his voice, and ask when he'll be back. He tells me shortly, so I reply by asking him to meet me in my room. He agrees, so I head inside.
~t+1:30 - I flash my ID to the security officer and quickly head into the elevator. The quick temperature change helps me come back, but only for a short moment again. I hit the button for my floor, and listen to the familiar beeps as the elevator passes each floor. But wait; there's too many beeps, and several will beep too close together, and then a long pause. I look at the numbers, but i'm not going anywhere. The floor indicator jumps from 1 to 2 to 3, but then back to 2, and then up to 5, and back down to 4. I fear as if I'm not moving, and want to get off the elevator.
~t+1:31 - I reach my floor, and make it back to my room. I don't want to wake my roommate, so I sit down next to my door and wait for my friend to arrive. My mind is still telling me I'm in my other friends room, so I close my eyes and try to 'wake up'.
~t+1:40 - I open my eyes to see my friend. standing over me. He says I was curled up in the fetal position, outside my neighbors door. I'm still convinced it was mine... We head down to his floor, and I hold the elevator for him. He comes back and enters the elevator. I stop and look at him. My mind is convinced I'm dreaming. Everything seems so quiet and unreal. I tell my friend to punch me, and he questions me. He questions my request several times, and I finally tell him to just do it. He does, and it makes me feel so much better. 'I wouldn't feel that in a dream' I tell myself.
~t+1:41 - The ride down isn't so bad. I get outside, but the fresh air doesn't help me any this time. My friend lights up a cigarette, and everything still seems like it's in fast-forward. I watch the tobacco quickly burn, but he's not saying much. I think I tried to explain what I was feeling, but I couldn't get the words out. He just keeps asking 'How much did I take?' I get that feeling that I'm dreaming again. I tell him that I'm going to bed, and he suggests it's a good idea.
~t+1:50 - I make it up to my room and into my bed, fully clothed.  I realize that I've got it, and hope that this isn't a dream. It seems to take forever to get to sleep, but I finally do.
I've never experienced time and space distortion as badly as I did in this experience. The frozen people are cars, as well as time jumping around on my watch really started to scare me.
Overall, I would say I would definately mix the two again, but with someone to accompany me the entire time.
My previous experiences with 2C-E have never been so strong, but I think that may also be because before I was looking for a good time, and this time I was looking for the full experience. I'll probably use a lower dosage if ever mixing the two again.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


The ideal solution to this would actually be to turn the graph into a 3D braille model so it can be printed. Due to conditions of remoteness and the time required to do such a task though, this is not possible right now.
Please do not navigate to connections manually. Use the links.


ANECREAM - lidocaine cream
Focus Health Group
Disclaimer: Most OTC drugs are not reviewed and approved by FDA, however they may be marketed if they comply with applicable regulations and policies. FDA has not evaluated whether this product complies.
Active Ingredient:
Lidocaine 4% w/w
Purpose
Topical anesthetic
Use:
temporarily relieves pain and itching due to:
- minor cuts
- minor scrapes
- sunburn
- minor skin irritations
- minor burns
- insect bites
WARNINGS:
For external use only.
When using this product
- do not use in or near the eyes
- do not use in large quantities, particularly over raw surfaces or blistered areas
Stop use and ask doctor if
- Allergic reaction occurs
- condition worsens or does not improve within 7 days
- symptoms clear up and return within a few days
- redness, irritation, swelling, pain or other symptoms begin or increase
Keep out of reach of children.
If swallowed, get medical help or contact a Poison Control Center right away
Directions:
- Adults and children 2 years and older: Apply externally to the affected area up to 3-4 times daily.
- Children under 2 years of age: Consult a doctor.
Other Information
Store at USP controlled room temperature 20-25 deg.C (68-77 deg.F).
Inactive ingredients
benzyl alcohol, carbomer 940,
cholesterol, hydrogenated lecithin, polysorbate 80, propylene glycol, tocopherol acetate, trolamine, water.
Anecream 30g Tube
The product package shown below represents a sample of that currently in use. Additional packaging may also be available.
Anecream Topical Anesthetic Cream
Net. Wt. 30g
Distributed by: Focus Health Group
Knoxville, TN 37919
ANECREAM 30G CARTON


Preact Phiber allows you to render components in streamable chunks (like large JPEGs on a dial up connection) so that a component, its children, its aunts and uncles, its first, second & third (not fourth because minimal) cousins, and its maternal grandparents can load asynchronously. Our priority system (aka, family free favoritism) allows for full interactivity before the bundle even finishes loading.


This post is a continuation of a series of posts about WebGL. The first started with fundamentals and the previous was about animation.
How do we apply textures in WebGL? You could probably derive how by reading the articles on image processing but it will probably be easier to understand if we go over it in more detail.
The first thing we need to do is adjust our shaders to use textures. Here are the changes to the vertex shader. We need to pass in texture coordinates. In this case we just pass them straight through to the fragment shader.
#version 300 es
in vec4 a_position;
*in vec2 a_texcoord;
uniform mat4 u_matrix;
+// a varying to pass the texture coordinates to the fragment shader
+out vec2 v_texcoord;
void main() {
// Multiply the position by the matrix.
gl_Position = u_matrix * a_position;
+ // Pass the texcoord to the fragment shader.
+ v_texcoord = a_texcoord;
}
In the fragment shader we declare a uniform sampler2D which lets us reference
a texture. We use the texture coordinates passed from the vertex shader
and we call texture
to look up a color from that texture.
#version 300 es
precision mediump float;
// Passed in from the vertex shader.
*in vec2 v_texcoord;
*// The texture.
*uniform sampler2D u_texture;
out vec4 outColor;
void main() {
* outColor = texture(u_texture, v_texcoord);
}
We need to setup the texture coordinates
// look up where the vertex data needs to go.
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
*var texcoordAttributeLocation = gl.getAttribLocation(program, "a_texcoord");
...
*// create the texcoord buffer, make it the current ARRAY_BUFFER
*// and copy in the texcoord values
*var texcoordBuffer = gl.createBuffer();
*gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
*setTexcoords(gl);
*
*// Turn on the attribute
*gl.enableVertexAttribArray(texcoordAttributeLocation);
*
*// Tell the attribute how to get data out of colorBuffer (ARRAY_BUFFER)
*var size = 2; // 2 components per iteration
*var type = gl.FLOAT; // the data is 32bit floating point values
*var normalize = true; // convert from 0-255 to 0.0-1.0
*var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next color
*var offset = 0; // start at the beginning of the buffer
*gl.vertexAttribPointer(
* texcoordAttributeLocation, size, type, normalize, stride, offset);
And you can see the coordinates we're using which are mapping the entire texture to each quad on our 'F'.
*// Fill the buffer with texture coordinates for the F.
*function setTexcoords(gl) {
* gl.bufferData(
* gl.ARRAY_BUFFER,
* new Float32Array([
* // left column front
* 0, 0,
* 0, 1,
* 1, 0,
* 0, 1,
* 1, 1,
* 1, 0,
*
* // top rung front
* 0, 0,
* 0, 1,
* 1, 0,
* 0, 1,
* 1, 1,
* 1, 0,
* ...
* ]),
* gl.STATIC_DRAW);
We also need a texture. We could make one from scratch but in this case let's load an image since that's probably the most common way.
Here's the image we're going to use
What an exciting image! Actually an image with an 'F' on it has a clear direction so it's easy to tell if it's turned or flipped etc when we use it as a texture.
The thing about loading an image is it happens asynchronously. We request the image to be loaded but it takes a while for the browser to download it. There are generally 2 solutions to this. We could make the code wait until the texture has downloaded and only then start drawing. The other solution is to make up some texture to use until the image is downloaded. That way we can start rendering immediately. Then, once the image has been downloaded we copy the image to the texture. We'll use that method below.
*// Create a texture.
*var texture = gl.createTexture();
*gl.bindTexture(gl.TEXTURE_2D, texture);
*
*// Fill the texture with a 1x1 blue pixel.
*gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
* new Uint8Array([0, 0, 255, 255]));
*
*// Asynchronously load an image
*var image = new Image();
*image.src = "resources/f-texture.png";
*image.addEventListener('load', function() {
* // Now that the image has loaded make copy it to the texture.
* gl.bindTexture(gl.TEXTURE_2D, texture);
* gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA,gl.UNSIGNED_BYTE, image);
* gl.generateMipmap(gl.TEXTURE_2D);
*});
And here it is
What if we wanted to just use a part of the texture across the front of the 'F'? Textures are referenced with "texture coordinates" and texture coordinates go from 0.0 to 1.0 from left to right across the texture and 0.0 to 1.0 from the first pixel on the first line to the last pixel on the last line. Notice I didn't stay top or bottom. Top and bottom make no sense in texture space because until you draw something and orient it there is no top and bottom. What matters is you supply texture data to WebGL. The start of that data starts at texture coordinate 0,0 and the end of that data is at 1,1
I loaded the texture into photoshop and looked up the various coordinates in pixels.
To convert from pixel coordinates to texture coordinates we can just use
texcoordX = pixelCoordX / (width - 1)
texcoordY = pixelCoordY / (height - 1)
Here are the texture coordinates for the front.
// left column front
38 / 255, 44 / 255,
38 / 255, 223 / 255,
113 / 255, 44 / 255,
38 / 255, 223 / 255,
113 / 255, 223 / 255,
113 / 255, 44 / 255,
// top rung front
113 / 255, 44 / 255,
113 / 255, 85 / 255,
218 / 255, 44 / 255,
113 / 255, 85 / 255,
218 / 255, 85 / 255,
218 / 255, 44 / 255,
// middle rung front
113 / 255, 112 / 255,
113 / 255, 151 / 255,
203 / 255, 112 / 255,
113 / 255, 151 / 255,
203 / 255, 151 / 255,
203 / 255, 112 / 255,
I also used similar texture coordinates for the back. And here it is.
Not a very exciting display but hopefully it demonstrates how to use texture coordinates. If you're making geometry in code (cubes, spheres, etc) it's usually pretty easy to compute whatever texture coordinates you want. On the other hand if you're getting 3d models from 3d modeling software like Blender, Maya, 3D Studio Max, then your artists (or you) will adjust texture coordinates in those packages using a UV editor.
So what happens if we use texture coordinates outside the 0.0 to 1.0 range. By default WebGL repeats the texture. 0.0 to 1.0 is one 'copy' of the texture. 1.0 to 2.0 is another copy. even -4.0 to -3.0 is yet another copy. Let's display a plane using these texture coordinates.
-3, -1,
2, -1,
-3, 4,
-3, 4,
2, -1,
2, 4,
and here it is
You can tell WebGL to not repeat the texture in a certain direction by using CLAMP_TO_EDGE
. For example
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
you can also tell WebGL to mirror the texture when it repeat use gl.MIRRORED_REPEAT
.
Click the buttons in the sample above to see the difference.
You might have noticed a call to gl.generateMipmap
back when we loaded the texture. What is that for?
Imagine we had this 16x16 pixel texture.
Now imagine we tried to draw that texture on a polygon 2x2 pixels big on the screen. What colors should we make those 4 pixels? There are 256 pixels to choose from. In Photoshop if you scaled a 16x16 pixel image to 2x2 it would average the 8x8 pixels in each corner to make the 4 pixels in a 2x2 image. Unfortunately reading 64 pixels and averaging them all together would be way too slow for a GPU.  To do what Photoshop does for each of the 4 pixels in the 2x2 result it would have to average 1024x1024 pixel or 1 million pixels times 4. That's way way too much to do and still be fast.
So what the GPU does is it uses a mipmap. A mipmap is a collection of progressively smaller images, each one 1/4th the size of the previous one. The mipmap for the 16x16 texture above would look something like this.
Generally each smaller level is just a bilinear interpolation of the previous level and that's
what gl.generateMipmap
does. It looks at the biggest level and generates all the smaller levels for you.
Of course you can supply the smaller levels yourself if you want.
Now if you try to draw that 16x16 pixel texture only 2x2 pixels on the screen WebGL can select the mip that's 2x2 which has already been averaged from the previous mips.
You can choose what WebGL does by setting the texture filtering for each texture. There are 6 modes
NEAREST
= choose 1 pixel from the biggest mipLINEAR
= choose 4 pixels from the biggest mip and blend themNEAREST_MIPMAP_NEAREST
= choose the best mip, then pick one pixel from that mipLINEAR_MIPMAP_NEAREST
= choose the best mip, then blend 4 pixels from that mipNEAREST_MIPMAP_LINEAR
= choose the best 2 mips, choose 1 pixel from each, blend themLINEAR_MIPMAP_LINEAR
= choose the best 2 mips. choose 4 pixels from each, blend themYou can see the importance of mips in these 2 examples. The first one shows that if you use NEAREST
or LINEAR
and only pick from the largest image then you'll get a lot of flickering because as things
move, for each pixel it draws it has to pick a single pixel from the largest image. That changes depending
on the size and position and so sometimes it will pick one pixel, other times a different one and so it
flickers.
The example above is exaggerated to show the issue.
Notice how much the ones on the left and middle flicker where as the ones on the right flicker less.
The ones on the right also have blended colors since they are using the mips. The smaller you draw the texture the further apart WebGL is
going to pick pixels. That's why for example the bottom middle one, even though it's using LINEAR
and blending
4 pixels it flickers different colors because those 4 pixels are from different corners of the 16x16 image depending on which
4 are picked you'll get a different color. The one on the bottom right though stays a consistent color
because it's using the 2nd to the smallest mip.
This second example shows polygons that go deep into the distance.
The 6 beams going into the screen are using the 6 filtering modes listed above. The top left beam is using NEAREST
and you can see it's clearly very blocky. The top middle is using LINEAR
and it's not much better.
The top right is using NEAREST_MIPMAP_NEAREST
. Click on the image to switch to a texture where every mip is
a different color and you'll easily see where it chooses to use a specific mip. The bottom left is using
LINEAR_MIPMAP_NEAREST
meaning it picks the best mip and then blends 4 pixels within that mip. You can still see
a clear area where it switches from one mip to the next mip. The bottom middle is using NEAREST_MIPMAP_LINEAR
meaning picking the best 2 mips, picking one pixel from each and blending
them. If you look close you can see how it's still blocky, especially in the horizontal direction.
The bottom right is using LINEAR_MIPMAP_LINEAR
which is picking the best 2 mips, picking 4 pixels from each,
and blends all 8 pixels.
You might be thinking why would you ever pick anything other than LINEAR_MIPMAP_LINEAR
which is arguably
the best one. There are many reasons. One is that LINEAR_MIPMAP_LINEAR
is the slowest. Reading 8 pixels
is slower than reading 1 pixel. On modern GPU hardware it's probably not an issue if you are only using 1
texture at a time but modern games might use 2 to 4 textures at once. 4 textures * 8 pixels per texture =
needing to read 32 pixels for every pixel drawn. That's going to be slow. Another reason is if you're trying
to achieve a certain effect. For example if you want something to have that pixelated retro look maybe you
want to use NEAREST
. Mips also take memory. In fact they take 33% more memory. That can be a lot of memory
especially for a very large texture like you might use on a title screen of a game. If you are never going
to draw something smaller than the largest mip why waste memory for the smaller mips. Instead just use NEAREST
or LINEAR
as they only ever use the first mip.
To set filtering you call gl.texParameter
like this
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
TEXTURE_MIN_FILTER
is the setting used when the size you are drawing is smaller than the largest mip.
TEXTURE_MAG_FILTER
is the setting used when the size you are drawing is larger than the largest mip. For
TEXTURE_MAG_FILTER
only NEAREST
and LINEAR
are valid settings.
Something to be aware of, WebGL2 requires textures to be "texture complete" otherwise they won't render. "texture complete" means that either
You've set the filtering so it only uses the first mip level which means
settting the TEXTURE_MIN_FILTER
to either LINEAR
or NEAREST
.
If you are using mips then they need to be the correct sizes and you have to provide ALL OF THEM down to the 1x1 size.
The easiest way to do that is to call gl.generateMipmap
. Otherwise if you provide your own mips you need to provide
all of them or you'll get an error.
A common question is "How do I apply a different image to each face of a cube?". For example let's say we had these 6 images.
3 answers come to mind
make a complicated shader that references 6 textures and pass in some extra per vertex info into the vertex shader that gets passed to the fragment shader to decide which texture to use. DON'T DO THIS! A little thought would make it clear that you'd end up having to write tons of different shaders if you wanted to do the same thing for different shapes with more sides etc.
draw 6 planes instead of a cube. This is a common solution. It's not bad but it also only really works for small shapes like a cube. If you had a sphere with 1000 quads and you wanted to put a different texture on each quad you'd have to draw 1000 planes and that would be slow.
The, dare I say, best solution is to put all of the images in 1 texture and use texture coordinates to map a different part of the texture to each face of the cube. This is the technique that pretty much all high performance apps (read games) use. So for example we'd put all the images in one texture possibly like this
and then use a different set of texture coordinates for each face of the cube.
// select the bottom left image
0 , 0 ,
0 , 0.5,
0.25, 0 ,
0 , 0.5,
0.25, 0.5,
0.25, 0 ,
// select the bottom middle image
0.25, 0 ,
0.5 , 0 ,
0.25, 0.5,
0.25, 0.5,
0.5 , 0 ,
0.5 , 0.5,
// select to bottom right image
0.5 , 0 ,
0.5 , 0.5,
0.75, 0 ,
0.5 , 0.5,
0.75, 0.5,
0.75, 0 ,
// select the top left image
0 , 0.5,
0.25, 0.5,
0 , 1 ,
0 , 1 ,
0.25, 0.5,
0.25, 1 ,
// select the top middle image
0.25, 0.5,
0.25, 1 ,
0.5 , 0.5,
0.25, 1 ,
0.5 , 1 ,
0.5 , 0.5,
// select the top right image
0.5 , 0.5,
0.75, 0.5,
0.5 , 1 ,
0.5 , 1 ,
0.75, 0.5,
0.75, 1 ,
And we get
This style of applying multiple images using 1 texture is often called a texture atlas. It's best because there's just 1 texture to load, the shader stays simple as it only has to reference 1 texture, and it only requires 1 draw call to draw the shape instead of 1 draw call per texture as it might if we split it into planes.
Next up lets start simplifying with less code more fun.


Adjust Web View SDK Demo App
Track Simple event
Track Revenue event
Track Callback event
Track Partner event
Enable Offline mode
Disable Offline mode
Enable SDK
Disable SDK
Is SDK Enabled?
Get Google Ad Id


LYTACs, or lysosome targeting chimeras, are promising tools to degrade extracellular proteins, that are responsible for 40% of cancers. These "chimera"s feature a target binding region which binds to these proteins, and a receptor binding ligand which transports the proteins into the lysosome where they are selectively degraded. What's more, LYTACs can serve as efficient biological probes as well! In this session, the speaker tries to explain to us how the scientists synthesized LYTACs aimed at degrading proteins in a cell-specific manner, and how on optimal modification they can also degrade integrins and block cancer cell proliferation.
With the atmospheric CO2 levels rising with a worrying persistence, the idea of capturing and possibly converting the polluting gas into useful green fuels, such as CO for syngas (CO+H2) production, has attracted much attention. However, this generally happens at the cost of harsh conditions and harmful byproducts. The paper discusses the recent discovery of a copper-indium oxide that converts CO2 to CO at the fastest rate and lower temperatures known is indeed groundbreaking!
Diels Alder reaction is one of the most celebrated reactions in organic chemistry. It was first described by Otto Diels and Kurt Alder in 1928. Although it has been over 90 years since its first use and over 70 years since it received the Nobel Prize, it excites chemists even today to the same extent as it did in the past. It has widespread applications in fields varying from natural product synthesis to modern material sciences besides many others. In spite of its extensive usage in natural and artificial systems, very few enzymes that catalyse Diels Alder reactions (Diels Alderases) have been found. There have been several attempts at making such artificial catalysts and they use various approaches like Lewis acid catalysis, Antibody catalysis and RNA catalysis to name a few.  The current paper takes a unique approach to solve these problems. This paper exploits the Lewis acid catalysis mechanism using a metalloenzyme which has a completely artificially synthesized protein part and Zinc as the metal. This approach is unique towards making artificial enzymes, as the previous attempts only included making changes to the active sites of natural enzymes. This paper discusses the design and development of this catalyst evolving from a 97-amino acid, naive zinc binding protein motif (generation zero) to an efficient, stereoselective and pathway selective catalyst (generation seven) by computational as well as synthetic methods in great details. The characterization of enzyme further shows a turnover number >104 per site and has the highest catalytic proficiency (2.9x1010 M-1 ) among all the previously synthesized enzymes. The extension of this approach, applied in the field of designing catalysts promises some exciting results.
Diels Alder reaction is one of the most celebrated reactions in organic chemistry. It was first described by Otto Diels and Kurt Alder in 1928. Although it has been over 90 years since its first use and over 70 years since it received the Nobel Prize, it excites chemists even today to the same extent as it did in the past. It has widespread applications in fields varying from natural product synthesis to modern material sciences besides many others. In spite of its extensive usage in natural and artificial systems, very few enzymes that catalyse Diels Alder reactions (Diels Alderases) have been found. There have been several attempts at making such artificial catalysts and they use various approaches like Lewis acid catalysis, Antibody catalysis and RNA catalysis to name a few.  The current paper takes a unique approach to solve these problems. This paper exploits the Lewis acid catalysis mechanism using a metalloenzyme which has a completely artificially synthesized protein part and Zinc as the metal. This approach is unique towards making artificial enzymes, as the previous attempts only included making changes to the active sites of natural enzymes. This paper discusses the design and development of this catalyst evolving from a 97-amino acid, naive zinc binding protein motif (generation zero) to an efficient, stereoselective and pathway selective catalyst (generation seven) by computational as well as synthetic methods in great details. The characterization of enzyme further shows a turnover number >104 per site and has the highest catalytic proficiency (2.9x1010 M-1 ) among all the previously synthesized enzymes. The extension of this approach, applied in the field of designing catalysts promises some exciting results.


This class is the base of all primitives in S3D. More...
#include <S3DPrimitive.h>
Public Member Functions | |
| virtual void | draw (S3DDevice *disp, S3DSurface window, S3DContext gc, S3DZBuffer *zbuffer)=0 |
| Virtual method. Implementations are responsible for drawing the primitive. | |
| virtual void | rotate (double rx, double ry, double rz, S3DPoint *anchor=NULL)=0 |
| Virtual method. Implementations are responsible for rotating the primitive. | |
| virtual void | move (double dx, double dy, double dz)=0 |
| Virtual method. Implementations are responsible for moving the primitive. | |
| virtual double | getZ ()=0 |
| Virtual method. Implementations are responsible for return some z-Value the primitive. | |
| bool | getFillMode () |
| Returns if the primitive is filled or just wireframe. | |
| void | setFillMode (bool fill) |
| Used to influence, if the primitive is filled or just wireframe. | |
| unsigned long | getColor () |
| Returns the color of the primitive. | |
| void | setColor (unsigned long c) |
| Sets the color of the primitive. | |
Public Attributes | |
| unsigned int | id |
Static Public Attributes | |
| static unsigned int | id_max = 1 |
Protected Attributes | |
| bool | isFilled |
| unsigned long | color |
This class is the base of all primitives in S3D.
This class is the base-class for ALL primitives in S3D. It contains the virtual methods, derived primitives need to implement. Its the main interface for primitives.
| void S3DPrimitive::setColor | ( | unsigned long | c | ) |
Sets the color of the primitive.
| [in] | c | The color as unsigned long (as produced by RGB-macro), the primitive will get. |
Reimplemented in S3DCube, S3DLine, S3DRect, S3DTetraeder, and S3DTriangle.
| void S3DPrimitive::setFillMode | ( | bool | fill | ) |
Used to influence, if the primitive is filled or just wireframe.
| [in] | fill | True, to make the primitive filled, else false. |


|
JavaTM 2 Platform Standard Ed. 5.0 |
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object java.awt.AWTKeyStroke
public class AWTKeyStroke
An AWTKeyStroke
represents a key action on the
keyboard, or equivalent input device. AWTKeyStroke
s
can correspond to only a press or release of a
particular key, just as KEY_PRESSED
and
KEY_RELEASED
KeyEvent
s do;
alternately, they can correspond to typing a specific Java character, just
as KEY_TYPED
KeyEvent
s do.
In all cases, AWTKeyStroke
s can specify modifiers
(alt, shift, control, meta, or a combination thereof) which must be present
during the action for an exact match.
AWTKeyStrokes
are immutable, and are intended
to be unique. Client code should never create an
AWTKeyStroke
on its own, but should instead use
a variant of getAWTKeyStroke
. Client use of these factory
methods allows the AWTKeyStroke
implementation
to cache and share instances efficiently.
getAWTKeyStroke(char)
,
Serialized Form| Constructor Summary | |
|---|---|
protected |
AWTKeyStroke()
Constructs an AWTKeyStroke with default values. |
protected |
AWTKeyStroke(char keyChar,
int keyCode,
int modifiers,
boolean onKeyRelease)
Constructs an AWTKeyStroke with the specified
values. |
| Method Summary | |
|---|---|
boolean |
equals(Object anObject)
Returns true if this object is identical to the specified object. |
static AWTKeyStroke |
getAWTKeyStroke(char keyChar)
Returns a shared instance of an AWTKeyStroke
that represents a KEY_TYPED event for the
specified character. |
static AWTKeyStroke |
getAWTKeyStroke(Character keyChar,
int modifiers)
Returns a shared instance of an AWTKeyStroke ,
given a Character object and a set of modifiers. |
static AWTKeyStroke |
getAWTKeyStroke(int keyCode,
int modifiers)
Returns a shared instance of an AWTKeyStroke ,
given a numeric key code and a set of modifiers. |
static AWTKeyStroke |
getAWTKeyStroke(int keyCode,
int modifiers,
boolean onKeyRelease)
Returns a shared instance of an AWTKeyStroke ,
given a numeric key code and a set of modifiers, specifying
whether the key is activated when it is pressed or released. |
static AWTKeyStroke |
getAWTKeyStroke(String s)
Parses a string and returns an AWTKeyStroke . |
static AWTKeyStroke |
getAWTKeyStrokeForEvent(KeyEvent anEvent)
Returns an AWTKeyStroke which represents the
stroke which generated a given KeyEvent . |
char |
getKeyChar()
Returns the character for this AWTKeyStroke . |
int |
getKeyCode()
Returns the numeric key code for this AWTKeyStroke . |
int |
getKeyEventType()
Returns the type of KeyEvent which corresponds to
this AWTKeyStroke . |
int |
getModifiers()
Returns the modifier keys for this AWTKeyStroke . |
int |
hashCode()
Returns a numeric value for this object that is likely to be unique, making it a good choice as the index value in a hash table. |
boolean |
isOnKeyRelease()
Returns whether this AWTKeyStroke represents a key release. |
protected Object |
readResolve()
Returns a cached instance of AWTKeyStroke (or a subclass of
AWTKeyStroke ) which is equal to this instance. |
protected static void |
registerSubclass(Class<?> subclass)
Registers a new class which the factory methods in AWTKeyStroke will use when generating new
instances of AWTKeyStroke s. |
String |
toString()
Returns a string that displays and identifies this object's properties. |
| Methods inherited from class java.lang.Object |
|---|
clone, finalize, getClass, notify, notifyAll, wait, wait, wait |
| Constructor Detail |
|---|
protected AWTKeyStroke()
AWTKeyStroke
with default values.
The default values used are:
| Property | Default Value |
|---|---|
| Key Char | KeyEvent.CHAR_UNDEFINED |
| Key Code | KeyEvent.VK_UNDEFINED |
| Modifiers | none |
| On key release? | false |
AWTKeyStroke
s should not be constructed
by client code. Use a variant of getAWTKeyStroke
instead.
getAWTKeyStroke(char)
protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
AWTKeyStroke
with the specified
values. AWTKeyStroke
s should not be constructed
by client code. Use a variant of getAWTKeyStroke
instead.
keyChar
- the character value for a keyboard keykeyCode
- the key code for this AWTKeyStroke
modifiers
- a bitwise-ored combination of any modifiersonKeyRelease
- true
if this
AWTKeyStroke
corresponds
to a key release; false
otherwisegetAWTKeyStroke(char)
| Method Detail |
|---|
protected static void registerSubclass(Class<?> subclass)
AWTKeyStroke
will use when generating new
instances of AWTKeyStroke
s. After invoking this
method, the factory methods will return instances of the specified
Class. The specified Class must be either AWTKeyStroke
or derived from AWTKeyStroke
, and it must have a
no-arg constructor. The constructor can be of any accessibility,
including private
. This operation
flushes the current AWTKeyStroke
cache.
subclass
- the new Class of which the factory methods should create
instances
IllegalArgumentException
- if subclass is null
,
or if subclass does not have a no-arg constructor
ClassCastException
- if subclass is not
AWTKeyStroke
, or a class derived from
AWTKeyStroke
public static AWTKeyStroke getAWTKeyStroke(char keyChar)
AWTKeyStroke
that represents a KEY_TYPED
event for the
specified character.
keyChar
- the character value for a keyboard key
AWTKeyStroke
object for that keypublic static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers)
AWTKeyStroke
,
given a Character object and a set of modifiers. Note
that the first parameter is of type Character rather than
char. This is to avoid inadvertent clashes with
calls to getAWTKeyStroke(int keyCode, int modifiers)
.
The modifiers consist of any combination of:
keyChar
- the Character object for a keyboard charactermodifiers
- a bitwise-ored combination of any modifiers
AWTKeyStroke
object for that key
IllegalArgumentException
- if keyChar
is
null
InputEvent
public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, boolean onKeyRelease)
AWTKeyStroke
,
given a numeric key code and a set of modifiers, specifying
whether the key is activated when it is pressed or released.
The "virtual key" constants defined in
java.awt.event.KeyEvent
can be
used to specify the key code. For example:
java.awt.event.KeyEvent.VK_ENTER
java.awt.event.KeyEvent.VK_TAB
java.awt.event.KeyEvent.VK_SPACE
keyCode
- an int specifying the numeric code for a keyboard keymodifiers
- a bitwise-ored combination of any modifiersonKeyRelease
- true
if the AWTKeyStroke
should represent a key release; false
otherwise
KeyEvent
,
InputEvent
public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers)
AWTKeyStroke
,
given a numeric key code and a set of modifiers. The returned
AWTKeyStroke
will correspond to a key press.
The "virtual key" constants defined in
java.awt.event.KeyEvent
can be
used to specify the key code. For example:
java.awt.event.KeyEvent.VK_ENTER
java.awt.event.KeyEvent.VK_TAB
java.awt.event.KeyEvent.VK_SPACE
keyCode
- an int specifying the numeric code for a keyboard keymodifiers
- a bitwise-ored combination of any modifiers
AWTKeyStroke
object for that keyKeyEvent
,
InputEvent
public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent)
AWTKeyStroke
which represents the
stroke which generated a given KeyEvent
.
This method obtains the keyChar from a KeyTyped
event, and the keyCode from a KeyPressed
or
KeyReleased
event. The KeyEvent
modifiers are
obtained for all three types of KeyEvent
.
anEvent
- the KeyEvent
from which to
obtain the AWTKeyStroke
AWTKeyStroke
that precipitated the event
NullPointerException
- if anEvent
is nullpublic static AWTKeyStroke getAWTKeyStroke(String s)
AWTKeyStroke
.
The string must have the following syntax:
<modifiers>* (<typedID> | <pressedReleasedID>) modifiers := shift | control | ctrl | meta | alt | altGraph typedID := typed <typedKey> typedKey := string of length 1 giving Unicode character. pressedReleasedID := (pressed | released) key key := KeyEvent key code name, i.e. the name following "VK_".If typed, pressed or released is not specified, pressed is assumed. Here are some examples:
"INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0); "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK); "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK); "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true); "typed a" => getAWTKeyStroke('a');
s
- a String formatted as described above
AWTKeyStroke
object for that String
IllegalArgumentException
- if s
is null
,
or is formatted incorrectlypublic final char getKeyChar()
AWTKeyStroke
.
getAWTKeyStroke(char)
public final int getKeyCode()
AWTKeyStroke
.
getAWTKeyStroke(int,int)
public final int getModifiers()
AWTKeyStroke
.
getAWTKeyStroke(int,int)
public final boolean isOnKeyRelease()
AWTKeyStroke
represents a key release.
true
if this AWTKeyStroke
represents a key release; false
otherwisegetAWTKeyStroke(int,int,boolean)
public final int getKeyEventType()
KeyEvent
which corresponds to
this AWTKeyStroke
.
KeyEvent.KEY_PRESSED
,
KeyEvent.KEY_TYPED
,
or KeyEvent.KEY_RELEASED
KeyEvent
public int hashCode()
hashCode
in class Object
Object.equals(java.lang.Object)
,
Hashtable
public final boolean equals(Object anObject)
equals
in class Object
anObject
- the Object to compare this object to
Object.hashCode()
,
Hashtable
public String toString()
String
returned by this method can be passed
as a parameter to getAWTKeyStroke(String)
to produce
a key stroke equal to this key stroke.
toString
in class Object
getAWTKeyStroke(String)
protected Object readResolve() throws ObjectStreamException
AWTKeyStroke
(or a subclass of
AWTKeyStroke
) which is equal to this instance.
ObjectStreamException
|
JavaTM 2 Platform Standard Ed. 5.0 |
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Copyright © 2004, 2010 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Also see the documentation redistribution policy.


Sign Up
1
Your basic info
Name:
Rollno:
Email:
Password:
2
Your profile
Year:
1st Year
2nd Year
3rd Year
4th Year
Department:
Aerospace & Defense
Marine & Offshore
Consumer Goods & Retial
Life Sciences
Energy, Process & Utilities
Language:
English
Hindi
Marathi
Interests:
jobtype1
jobtype2
jobtype3
Sign Up


Real-time Profiling Monitor
/opt/stack/swift/swift/proxy/server.py:205(__call__)
0
20
40
60
80
100
Cumulative Time/Total Calls (ms/call)
Time Window(60 seconds)
+
Interval:
milliseconds
Server:
Profile:
all
current
Function:
:
(
)
Data:


ICNB 2016:
ICNB'16 will be held in Prague, Czech Republic on April 1 - 2, 2016 at the Clarion Congress Hotel Prague.
Best Paper Award:
Two best paper awards will be conferred to author(s) of the papers that receive the highest rank during the peer-review and by the respected session chairs. Please visit Paper Submission for more information.


Looking for a cleric build but for rp purposes would want to focus on cleric mixed in with some other classes to survive better but definitely have all the cleric abilities. I'm going to start playing on a high-magic server (at least I think it is) so not sure how that would change the build. Do you have to focus more on spellcasting on a high magic world to keep up with fighters? Or is it the other way around?


my
portfolio
A
R
T
Find Home
Even at nighttime
Send me a note
My version of a form
Send me a file
See this fileloader
Something
Lorem ipsum
Something
Lorem ipsum
Something
Lorem ipsum


Welcome!¶
Welcome to Easy SimAuto’s (ESA) documentation! If you encounter issues with ESA or the documentation, please file an issue on GitHub.
Citation¶
If you use ESA in any of your work, please use the citation below.
@article{ESA,
doi = {10.21105/joss.02289},
url = {https://doi.org/10.21105/joss.02289},
year = {2020},
publisher = {The Open Journal},
volume = {5},
number = {50},
pages = {2289},
author = {Brandon L. Thayer and Zeyu Mao and Yijing Liu and Katherine Davis and Thomas J. Overbye},
title = {Easy SimAuto (ESA): A Python Package that Simplifies Interacting with PowerWorld Simulator},
journal = {Journal of Open Source Software}
}
What Is ESA?¶
ESA is a “Pip-installable” Python package that eases interaction with the PowerWorld Simulator Automation Server (SimAuto). PowerWorld Simulator is a powerful, commercial-grade electric grid simulation tool with a wide range of capabilities. Information on Simulator can be found here and information on SimAuto can be found here. Since ESA directly interfaces with SimAuto, ESA users will need a PowerWorld license and installation that also includes SimAuto.
ESA makes working with SimAuto, well, easy. Users don’t have to worry about input or output data type conversions, data mapping, determining whether SimAuto has reported an error, and more. Additionally, ESA uses the scientific computing packages you know and love, including Numpy and Pandas. In addition to wrapping 100% of the functions provided by SimAuto, ESA provides helper functions that further ease development. Below is a quick motivating example (also found in Increase Loading in Case) that shows how easy it is to use SimAuto.
This simple example uniformly increases the loading in a power system model by 50%.
If you want to follow along, you’ll first need to define your own
CASE_PATH
constant (the file path to a PowerWorld .pwb
case
file), like so (adapt the path for your system):
CASE_PATH = r"C:\Users\myuser\git\ESA\tests\cases\ieee_14\IEEE 14 bus_pws_version_21.pwb"
Then, import the SimAuto wrapper (SAW) class and initialize an instance:
>>> from esa import SAW
>>> saw = SAW(CASE_PATH)
Retrieve key fields for loads:
>>> kf = saw.get_key_field_list('load')
>>> kf
['BusNum', 'LoadID']
Pull load data including active and reactive power demand:
>>> load_frame = saw.GetParametersMultipleElement('load', kf + ['LoadSMW', 'LoadSMVR'])
>>> load_frame
BusNum LoadID LoadSMW LoadSMVR
0 2 1 21.699999 12.700000
1 3 1 94.199997 19.000000
2 4 1 47.799999 -3.900000
3 5 1 7.600000 1.600000
4 6 1 11.200000 7.500000
5 9 1 29.499999 16.599999
6 10 1 9.000000 5.800000
7 11 1 3.500000 1.800000
8 12 1 6.100000 1.600000
9 13 1 13.500001 5.800000
10 14 1 14.900000 5.000000
To learn more about variables such as LoadSMW
, see
PowerWorld Variables.
Uniformly increase loading by 50% and solve the power flow:
>>> load_frame[['LoadSMW', 'LoadSMVR']] *= 1.5
>>> saw.change_parameters_multiple_element_df('load', load_frame)
>>> saw.SolvePowerFlow()
Let’s confirm that the loading did indeed increase:
>>> new_loads = saw.GetParametersMultipleElement('load', kf + ['LoadSMW', 'LoadSMVR'])
>>> new_loads
BusNum LoadID LoadSMW LoadSMVR
0 2 1 32.549998 19.050001
1 3 1 141.299999 28.500000
2 4 1 71.699995 -5.850000
3 5 1 11.400000 2.400000
4 6 1 16.800001 11.250000
5 9 1 44.250000 24.900000
6 10 1 13.500001 8.700000
7 11 1 5.250000 2.700000
8 12 1 9.150000 2.400000
9 13 1 20.250002 8.700000
10 14 1 22.350000 7.500000
Clean up when done:
>>> saw.exit()
Easy, isn’t it?
About SimAuto¶
From PowerWorld’s SimAuto page:
"The Simulator Automation Server (SimAuto) allows you to take
advantage of the power of automation to extend the functionality of
PowerWorld Simulator to any external program that you write. Using
Simulator Automation Server you can launch and control PowerWorld
Simulator from within another application, enabling you to: access
the data of a Simulator case, perform defined Simulator functions
and other data manipulations, and send results back to your original
application, to a Simulator auxiliary file, or to a Microsoft® Excel
spreadsheet."
In essence, SimAuto is PowerWorld Simulator’s application programming interface (API). As such, SimAuto users can perform almost any task that can be done through Simulator’s graphic user interface (GUI), but via their own program. This opens up a wealth of opportunity to perform tasks such as:
Task automation
Sensitivity analysis
Co-simulation
Machine learning
And more!
For more SimAuto details, here are some PowerWorld links:
Since SimAuto strives to be accessible to “any external” program and uses Windows COM, it can be cumbersome, tedious, and difficult to use. That’s where ESA comes in!
SimAuto Functions¶
Here’s a listing of the currently (as of 2020-06-17, Simulator version 21) available SimAuto functions (documented here):
ChangeParameters
ChangeParametersSingleElement
ChangeParametersMultipleElement
CloseCase
GetFieldList
GetParametersSingleElement
GetParametersMultipleElement
GetParameters
GetSpecificFieldList
GetSpecificFieldMaxNum
ListOfDevices
LoadState
OpenCase
ProcessAuxFile
SaveCase
SaveState
SendToExcel (not recommended for use with ESA as documented in esa.saw Module)
TSGetContingencyResults
WriteAuxFile
For ESA’s implementation/wrapping of these methods, see esa.saw Module.
SimAuto Properties¶
Here’s a listing of the currently (as of 2020-06-17, Simulator version 21) available SimAuto properties (documented here):
ExcelApp (like
SendToExcel
function, not recommended for use with ESA)CreateIfNotFound
CurrentDir
ProcessID
RequestBuildDate
UIVisible (Simulator versions >= 20)
For ESA’s implementation/wrapping of these properties, see esa.saw Module.
Who Should Use ESA?¶
ESA is useful for a wide range of audiences, including:
Industry practitioners (e.g. power system planners, energy traders, etc.)
Power system researchers
Researchers from other domains who wish to perform co-simulation with power system models
University students and faculty
Power system enthusiasts
ESA users should be proficient in Python, and it’s recommended that users get familiar with Numpy and Pandas, as ESA makes significant use of these packages. ESA users do not need to have any knowledge whatsoever related to how the Windows COM API works, nor do users need to be familiar with PyWin32.
Ultimately, ESA is a tool for interacting with PowerWorld Simulator -
thus, users should have some familiarity with Simulator. Users do not
need to directly understand how to use SimAuto, as ESA abstracts those
details away. Advanced users will have a solid understanding of
PowerWorld variables and object types, and will make extensive use of
the RunScriptCommand
method to enable the execution of PowerWorld
functions previously only accessible via “Auxiliary Files”.
Why Use ESA?¶
Simply put, ESA makes working with SimAuto a breeze! ESA has the following desirable properties:
Free, open-source, non-restrictive license
Fully documented, including a plethora of examples and common issues
Fully tested - rest assured that all functions work as intended
Abstracts away all interactions with Windows COM
Automatically parses errors from PowerWorld
Automatically transforms data into the correct types
Wraps all available SimAuto functions
Provides additional helper functions to further simplify interactions with SimAuto
Provides functions to interact with PowerWorld Simulator interface, without the hassle of creating and loading the display auxiliary files
Returns useful data types such as Pandas DataFrames, unlocking a whole new realm of analysis and control capabilities
Gets data from a power system model for other application, like graph analysis or signal processing
Co-simulation with other domains such as transportation, communication, or natural gas
Task automation, like dynamic model tuning and relay setting tuning
AI & ML friendly
Compatible with several modern Python versions
Lightweight and fast
Whether you’re an energy trader, transmission planner, or academic researcher, ESA will help simplify your simulation an analysis work flows.
Projects That Use ESA¶
ESA has already been utilized in several research projects past and present. If you use ESA in your work, please file an issue on GitHub and we’ll list your project here! Please cite ESA if you use it in your work: see Citation.
In gym-powerworld, ESA was used to create a standardized reinforcement learning environment for power system voltage control. This environment was then used to carry out deep reinforcement learning (DRL) experiments in which the algorithm attempts to learn how to best control grid voltages under a diverse set of grid conditions.
In this paper, ESA was leveraged to create and simulate different electric grid scenarios where load, renewable generation levels, generation capacities, scheduled outages, and unit commitment were all varied. The resulting scenarios were used in the Grid Optimization (GO) competition hosted by the U.S. Department of Energy (DOE).
Geomagnetic disturbances (GMDs) affect the magnetic and electric field of the earth, inducing dc voltage sources superimposed on transmission lines. In an accepted paper by Martinez et al. entitled “Undergraduate Research on Design Considerations for a GMD Mitigation Systems” (to be published in mid-late 2020), a planning-based GMD mitigation strategy was developed for large power systems. ESA is leveraged to programmatically place GIC blocking devices in test systems per the proposed algorithm, thus minimizing the effects of GMDs on the power grid.
ESA is used by an ongoing research project entitled “Real Time Monitoring Applications for the Power Grid under Geomagnetic Disturbances (GMD)”: Recently, a real-world GMD monitoring system consisting of six magnetometers was deployed in Texas. The resulting magnetic field measurements are coupled with ground conductivity models to calculate real-time electric fields. These can then be fed to a grid model of Texas using ESA to enable calculation of real-time geomagnetically induced currents (GICs) for monitoring and visualization.
ESA is used by an ongoing research project entitled “Contingency Analysis Based on Graph Theory Concepts and Line Outage Distribution Factors (LODF).” In this project, ESA is leveraged to extract the topology of the power system model and obtain the LODF matrix.
Disclaimer and Credits¶
Disclaimer¶
As noted in ESA’s license, no warranty is provided, and the authors cannot be held liable for any issues related to using ESA. If you encounter an issue, find a bug, or would like to provide feedback, please file a ticket on Github.
Credits and Thanks¶
ESA was developed at Texas A&M University by Brandon Thayer, Zeyu Mao, and Yijing Liu. Significant guidance and oversight was provided by Professor Thomas Overbye, who is a co-founder of PowerWorld Corporation, and Professor Katherine Davis, who is one of the original authors of SimAuto. Funding was provided by the Texas A&M Engineering Experiment Station’s Smart Grid Center and the U.S. Department of Energy (DOE) under award DE-OE0000895.
The authors of ESA would like to give a special thank you to our users. Additionally, we’ve received help from some of our colleagues along the way, including (but not limited to!) Wei Trinh and Diana Wallison. Thank you!
We hope you enjoy using ESA as much as we’ve enjoyed creating it.
Changelog¶
Changes made with each ESA release are listed here. Please note that versions prior to 1.0.0 are not listed here, but are still available on PyPi.
Version 1.0.7¶
Add new functions: get_ybus, get_jacobian
Version 1.0.6¶
Hopefully finally fixing locale-based issues. Fixes began in 1.0.4, and continued in 1.0.5.
Finalizing JOSS paper. Once published, the citation will be added to the top-level README and the documentation.
Version 1.0.5¶
It turns out version 1.0.4 did not fully/correctly handle automatic locale setting. This version should now properly handle different decimal delimiters automatically.
Bug fix: The
additional_fields
parameter toSAW
’sget_power_flow_results
was permanently adding theadditional_fields
to the corresponding list in theSAW
object’sSAW.POWER_FLOW_FIELDS
attribute.
Version 1.0.4¶
Added support for other locales by automatically detecting the system’s decimal delimiter. This should allow users in Europe and elsewhere to leverage ESA. Thanks to robinroche for pointing out the problem during our JOSS review in this comment.
Version 1.0.3¶
New SAW attribute,
build_date
New SAW attribute,
version
New SAW helper method,
get_version_and_builddate
Add argument
additional_fields
forget_power_flow_results
method which provides an easy and consistent way to add more fields to the power flow resultUpdating so that ESA is compatible with Simulator version 17. Note that this does not imply ESA has been tested with versions 16, 18, 19, or 20. However, ESA should work with all these versions.
Added case files for Simulator versions 16-22(beta) and renamed the cases accordingly (suffixed with
pws_version_<version goes here>.pwb
.Updated documentation to discuss different versions of Simulator.
Version 1.0.2¶
Add area number to the power flow result
Update the citation section
Fix a bug in the test file that will result in a failure if some default names are changed in PowerWorld
Version 1.0.1¶
Add new functions: update_ui, OpenOneline and CloseOneline
Add documents to meet the requirement of JOSS
Add one more example into the documentation
Update the coverage_to_rst.py so that it’s more clear that the errors that get printed during testing are as expected.
Update the release process
Fix minor typos
Version 1.0.0¶
ESA version 1.0.0 is the first ESA release in which 100% of SimAuto functions are wrapped, and testing coverage is at 100%.