|By Hal Helms||
|November 1, 2001 12:00 AM EST||
Someone once said that people should never see how laws or sausages are made. I think I can safely add technical standards to that list. There have been passionate arguments and some painful missteps along the way, but that's all eclipsed as people begin discovering the new power and ease-of-use in Fusebox 3.0.
What's New in Fusebox 3.0
Here's a rundown of some of the key features:
- A nested model for communication between circuits created to make reuse and distributed development easier
- A nested layout model that opens up possibilities for highly dynamic, flexible layouts
- XML-based Fusedoc providing both PDL (Program Definition Language) and documentation for fuses
- A stable set of key files that forms a Fusebox skeleton, making the learning process easier for people new to Fusebox and making it much easier to generate a new Fusebox application
- Exit fuseactions (XFAs) for greater reusability of fuses and circuits
- An API that exposes key variables within a Fusebox structure defined by the key Fusebox file
The core Fusebox files begin with an FBX_ prefix. A sample application is assumed with the circuit structure shown in Figure 1.
The component Fusebox files are:
This file is optional and is used to set variables that are needed by the application. Each circuit may have its own FBX_Settings.cfm file. If a fuseaction such as grandchild.main is resolved to home/parent/ child/grandchild.main, FBX_ Settings.cfm will be called in each directory in order. This allows you to set general variables at higher levels and override them, if needed, in child directories. This file replaces myGlobals.cfm, app_ Globals.cfm, and app_Locals.cfm.
Required in the home circuit, FBX_ Circuits.cfm maps circuit aliases to physical paths. In the sample application shown, the contents of FBX_Circuits.cfm are:
Fusebox.Circuits.home = 'Grandparent';
Fusebox.Circuits.parent = 'Grandparent/Parent';
Fusebox.Circuits.Child = 'Grandparent/Parent/Child';
Fusebox.Circuits.grandchild = 'Grandparent/Parent/Child/Grandchild';
The circuit alias is a key within a structure called Circuits, with the reserved structure Fusebox. The circuit alias doesn't have to be the same name as the physical directory, as shown by aliasing the top directory (Grandparent) as home. This allows for directories at different levels to have the same name.
This file is placed in every circuit that handles fuseactions; FBX_Switch.cfm is a <cfswitch> statement with <cfcase>s for every fuseaction the individual circuit is to handle.
Required in any circuit that implements a separate layout file, FBX_Layouts.cfm is responsible for setting the variables, Fusebox.layoutDir and Fusebox.layoutFile. The layout file pointed to in Fusebox.layoutFile must, at a minimum, output Fusebox.layout. Conditional processing is possible within FBX_Layouts.cfm. If, for example, a child sets a Boolean variable called QueryReturnedRecords, a parent might implement this simple logic in FBX_Layouts.cfm:
Used if the ColdFusion server version is below version 5.0, this file is the widely popular <cf_bodycontent> tag.
Of the files FBX_Fusebox30_CF50.cfm, FBX_Fusebox30_CF45.cfm, and FBX_Fusebox30_CF40.cfm, only one will be called in index.cfm, depending on which version of ColdFusion server is running. The index.cfm file should have this code in it:
<cfif Val(ListGetAt(Server.ColdFusion.ProductVersion, 1)) LT "5">
<cfif Val(ListGetAt(Server.ColdFusion.ProductVersion, 2)) is "5">
<cfinclude template="fbx_fusebox30 _CF45.cfm">
<cfinclude template="fbx_fusebox30_ CF40.cfm">
Note: If you create circuit applications, the only file that's absolutely required for a circuit that only runs beneath other circuits is the fbx_switch.cfm file. The other files are needed only if you have special settings to set and special layouts to handle. Circuits are defined only in the home circuit. Of course, you do have to supply your own fuseactions and fuses; we had to leave some of the work for you, after all!
In addition to the core Fusebox files, DefaultLayout.cfm is provided. This file simply outputs Fusebox.layout. This is a useful file when you don't care about a given circuit adding any layouts and simply want it to display the layout. Note, however, that while the fuseaction path must have one layout file, you don't need any files in circuits that don't have any special layout requirements. In the "family" application whose directory structure is shown in Figure 1, a request for grandchild.main might, for example, have layout handled in only one of the circuits involved. In such a case the other circuits wouldn't require an FBX_Layouts.cfm file nor the use of DefaultLayout.cfm.
Reserved Variables: The Fusebox 3.0 API
There are two complex variable structures. The first, the FB_ structure, is used for internal calculations by the FBX_Fusebox_CFxx.cfm file. You should neither read nor write to this structure since it will immediately render your code non-Fusebox 3.0-compliant and may well break your application.
The second reserved variable structure is the public "API" called Fusebox (see Table 1). Again, you shouldn't make any changes to this API. You'll find some variables within this structure very useful. You can use these public variables anywhere within your code, as any changes to the Fusebox standard will support these variables going forward, even if the underlying code that calculates these variables is modified.
Core Fusebox 3.0 Concepts
With the new terminology, API, and required files under our belts, let's turn our attention to the latest additions to the "core Fusebox" methodology that makes its appearance in Fusebox 3.0. These are exit fuseactions (XFAs), Fusedocs, and nested circuits.
XFAs address issues of severability and reuse; Fusedocs address code documentation, especially in a distributed developer environment; nested circuits address inheritance, layouts, and exception handling. Although these are largely separate concepts, they do weave into the overall Fusebox scheme and are absolutely essential toward realizing the advantages that Fusebox 3 can deliver.
Exit Fuseactions (XFAs)
The first of the new concepts for Fusebox 3.0 is exit fuseactions. XFAs are the identified exit points of a particular fuse. In Fusebox the meaning of an exit point is not "Where do we go next?" (we always go back to the fusebox!), but rather, "What fuseaction are we going to take upon our return to the fusebox?"
For example, take the case where a user fills out a form to win the $1 million we're giving away. The user begins by getting an exciting, unexpected e-mail from us (really, it's not spam!) on which appears a link (see Figure 2):
<a href="http://scamsRus.com/index.cfm? fuseaction=showContestForm">Click here to win a million dollars</a>
When the user submits that form, we want to store the information to a database while the user expectantly awaits a celebrity spokesperson's arrival with a substantial cashier's check. Regardless of what the spokesperson does, the form had only one possible way to return to the fusebox - by the user clicking the OK button. We might assign an exit fuseaction of "saveToDatabase" to that exit point, and represent it like this:
The problem with such a fuseaction is that it's a hard reference. To reuse the fuse - either in a new application or in a new context in the same application - I need to either change code or introduce conditional logic into the fuse. Neither path is optimal.
A much better way to handle our sample case is to identify the exit points of a fuse - those paths out of the fuse - and to assign variable names to them. The fuse then becomes completely independent of the application or context in which it operates, allowing it to be easily reused. The form code looks like this:
The value of XFA.submitForm is then set (by the architect) in the new FBX_ Switch.cfm file.
<cfset XFA.submitForm = "saveToDatabase">
Introducing XML Fusedocs
As programmers, we know that we should document our code, but we often create little or no documentation or, at best, documentation is done afterwards. At some firms documentation is taken much more seriously, but often the reason for that documentation is not conveyed. Without knowing why we should do something, how we should do it will never be clear. About the only thing that everyone seems to agree on is that documentation is something that's good for you, like castor oil. That was the old way.
Fusedoc is different. It's not about documenting your code; it's about coding your documentation. The Fusedoc process makes the application architect responsible for documenting the application before coding even starts. Fusedoc supplies all the information the coder needs to complete the fuse.
Fusedoc details exactly what the fuse is expected to do, and the variables and resources it uses and produces (inputs and outputs). It takes the form of a comment at the top of the fuse file.
<fusedoc fuse="fuse_name" version="2.0" language="ColdFusion">
fusedoc elements go hereŠ
In Fusebox 2.0, Fusedocs used a proprietary format that I developed. Starting with Fusebox 3.0, they're now XML-based. If you're familiar with XML, reading a Fusedoc is simple. If you're new to XML, you may find the Fusedoc to be a great confidence builder toward working more with XML.
We're trying to provide enough information so that a competent programmer, who knows nothing of the application nor of the underlying database, can write the code. It's sometimes referred to as programming by contract because the comments provided form a sort of "work order" that tells the coder exactly what to do. The "contract" promises the programmer, "You fulfill this work order and you will be done with the code. You have no responsibility beyond what the document tells you."
With Fusebox 3, Fusedoc goes from a proprietary symbology to the open standard of XML. There's a document type definition (DTD) available at www.halhelms.com that provides the formal specification for Fusedoc. To give you a taste of what one looks like, Listing 1 provides a complete Fusedoc for a fuse, act_ValidateLogin.cfm.
More information on Fusedocs and Fusebox 3.0 is available at www.halhelms. com.
Nesting Circuits and Layouts
In Fusebox 2, integration between separate fuseboxes consisted mainly of "tricks" for sending a browser from one insular fusebox to another. But the true goal is a "drag-and-drop" type of functionality, in which a fusebox consists of one of more circuits (a file directory), all of which can access each other without direct dependence on the underlying directory structure and that, when done, can be dragged-and-dropped to another fusebox, requiring only a few small settings to be changed to the definition of the circuits.
If this type of nesting is combined with some sort of a standard with respect to how a fusebox operates within its own framework, we're able to write large amounts of reusable code. If we continue to adhere strictly to a standard for doing that, like Fusebox 3.0, then people can write entire applications that can be stamped as "Fusebox 3.0-compliant" and then dropped into our own code, saving time and money.
Fusebox 3.0 has its own concept of inheritance that, while very different from object-oriented languages, allows children to inherit properties from their parent, grandparent, and so on. Each of these circuits can be "dragged-and-dropped" into a parent circuit, resembling those wooden Russian dolls in which one doll contains another one. This pattern continues for as long as the artistry of the maker can sustain itself. In Fusebox 3.0 the grandparent circuit may contain one or more parent circuits that may contain one or more child circuits, and so on.
Each circuit, from the top or home circuit and continuing down each intervening circuit to the target circuit, has a settings file called FBX_Settings.cfm. The more global an item in a settings file is, the "higher up" the circuits tree that item would be loaded. So if your application accesses a data source called customers, you may want to set Request.DSN in the home circuit.
Suppose you dropped in a shopping cart circuit that needs a products data source. It might set one as part of its own settings file since that DSN may only be needed by that circuit or one of its child circuits. Of course you, as the architect of your program, can determine whether you want to force it to have a certain value by using cfset or whether you want it to inherit a value from a higher-level circuit - if such a value has already been set - by using a cfparam. In earlier versions of Fusebox, you included the app_globals.cfm once and then used app_locals.cfm for all second-tier circuits. In Fusebox 3.0 there's no hard meaning to "global" or "local" - anything set in a circuit is available to all circuits nested beneath that circuit. Again, remember the Russian doll.
Fusebox automatically reads in any FBX_Settings.cfm files from all circuits in the fuseaction path. Once the target circuit is reached, FBX_Switch.cfm is called, executing the target fuseaction within that circuit. This concept has not changed from Fusebox 1.0.
The concept of nested layouts is a very exciting addition. Having walked "down" the fuseaction circuit tree and executed the fuseaction, Fusebox now walks "up" the tree from the bottom "target" circuit where the fuseaction was found, up through each parent circuit up to the home circuit. Each of those circuits, in order, will have the opportunity to apply its own layout as determined by the FBX_Layouts file, just as you might put a Russian doll back together - each of the larger dolls taking what they got from the smaller doll and wrapping their own wrapper around it. While you can make use of every circuit in the fuseaction path, you don't need to. Figure 3 is a teaching example that shows the use of layouts at each circuit in the fuseaction path.
Migrating from Fusebox 2 to Fusebox 3
The learning curve for FB3 has been made easy due primarily to the standardization of the underlying core Fusebox code combined with a standardization in the naming convention. For these same reasons your migration path from FB2 to FB3 will be fairly easy, especially after you've achieved your first application with the new standard.
What about some of the underlying files you've dealt with before? Well, app_locals.cfm and app_globals.cfm are now combined into a single file called FBX_Settings.cfm. Application.cfm is still not a required file since the functionality you might put there can be put into FBX_Settings.cfm as well.
If you were a fan of Steve Nelson's <cf_bodycontent> custom tag for "wrapping" layout with common design elements, that functionality is still there too. Now, though, you don't need a "header" and a "footer" file, rather you can define actual layout files that include both header and footer elements in a way that's fairly transparent. Again, the "frozen" core fusebox file will pick up your layout files as well.
In Fusebox 2, index.cfm (or the default document) had all the core functionality of Fusebox written into it. In Fusebox 3.0 a new file, FBX_Fusebox30_CFxx.cfm - where xx is a version that's appropriate for the version of the ColdFusion application server your machine is running - takes its place.
Circuits are a new idea for the standard, one that entirely replaces Fusebox 2's ad hoc "dot-dot-slash" method of making one fusebox talk to another. With Fusebox 2 a fuseaction usually had a verb-noun phrase syntax, such as addItem ToCart. In Fusebox 3, fuseactions are written with a circuit_ alias.fuseaction syntax. To solve the problem of circuits on different levels having the same name, an FBX_Circuits.cfm file has been introduced. It maps individual circuits to an alias of your choosing. Nesting/inheritance in Fusebox 3.0 is done for you automatically by the core fusebox file, FBX_Fusebox_CFxx.cfm, using the FBX_ Circuits.cfm file's mappings. Assume that we have an application with the circuit structure shown in Figure 4.
Assume that a fuse within the Granddaughter circuit executes this code:
The variable, self, is defined in the home circuit's FBX_ Settings.cfm as index.cfm (or default file) of the home circuit - Grandmother, in our case. In addition the variable XFA.continue is defined within FBX_Switch.cfm as Grandson.sayHello. All of this is under the control of the application architect.
All action returns to the home circuit's default file. This file includes the version of FBX_Fusebox30_CFxx.cfm that's appropriate for the ColdFusion server that's running. Within this file Fusebox translates the fuseaction, Grandson.sayHello, to the fuseaction path, in effect saying, "You said Grandson.sayHello, but I see from FBX_Circuits.cfm that what you really mean is Grandmother/Father/Son/Grandson.sayHello. Let me execute that for you." All that's required from you is that you properly map the circuits in FBX_Circuits.cfm, a very easy matter, and use the compound circuit_alias.fuseaction syntax.
Fusebox 3.0 represents a major landmark in the Fusebox community's approach to creating a methodology that consistently produces predictable success in Web application development, but it is just that - a landmark, a waystation in an ongoing journey. Fusebox began with ColdFusion and is being adopted by developers working in PHP, ASP, and JSP.
Where do we go from here? Much work remains to be done. With Fusebox 3.0 we've achieved a platform on which we can build even more firmly. In the coming months new work will begin on making ColdFusion even better. We hope that you'll be a part of this venture.
How can you be involved? First, join the Fusebox community officially by signing up at www.fusebox.org. Next, join the Fusebox mailing list; a signup form is available at www.halhelms.com. If you'd like to participate in making the future of Fusebox, sign up for the Fusebox steering mailing list by sending an e-mail to [email protected].
To learn more about being a contract "Fusecoder," check out Steve Nelson's Web site at www.secretagents.com. Lee Borkman is heading up an open-source effort to make wireframes even better; information is available at www.bjork.net. Jeff Peters has some wonderful tools available for Fusecoders at www.grokfusebox.com. John Quarto-vonTivadar has articles available at www.grokdotcom.com (free newsletter signup) and www.johnquarto.com. Finally, you may want to sign up for my free Occasional Newsletter at www.halhelms.com..
Alan Kay, the creator of the language Smalltalk, once said, "The best way to predict the future is to invent it." Let's get busy.
Connected devices and the Internet of Things are getting significant momentum in 2014. In his session at Internet of @ThingsExpo, Jim Hunter, Chief Scientist & Technology Evangelist at Greenwave Systems, examined three key elements that together will drive mass adoption of the IoT before the end of 2015. The first element is the recent advent of robust open source protocols (like AllJoyn and WebRTC) that facilitate M2M communication. The second is broad availability of flexible, cost-effective storage designed to handle the massive surge in back-end data in a world where timely analytics is e...
Nov. 26, 2014 11:45 PM EST Reads: 1,042
How do APIs and IoT relate? The answer is not as simple as merely adding an API on top of a dumb device, but rather about understanding the architectural patterns for implementing an IoT fabric. There are typically two or three trends: Exposing the device to a management framework Exposing that management framework to a business centric logic Exposing that business layer and data to end users. This last trend is the IoT stack, which involves a new shift in the separation of what stuff happens, where data lives and where the interface lies. For instance, it's a mix of architectural styles ...
Nov. 26, 2014 11:30 PM EST Reads: 930
The Internet of Things will put IT to its ultimate test by creating infinite new opportunities to digitize products and services, generate and analyze new data to improve customer satisfaction, and discover new ways to gain a competitive advantage across nearly every industry. In order to help corporate business units to capitalize on the rapidly evolving IoT opportunities, IT must stand up to a new set of challenges. In his session at @ThingsExpo, Jeff Kaplan, Managing Director of THINKstrategies, will examine why IT must finally fulfill its role in support of its SBUs or face a new round of...
Nov. 26, 2014 09:00 PM EST Reads: 1,000
We are reaching the end of the beginning with WebRTC, and real systems using this technology have begun to appear. One challenge that faces every WebRTC deployment (in some form or another) is identity management. For example, if you have an existing service – possibly built on a variety of different PaaS/SaaS offerings – and you want to add real-time communications you are faced with a challenge relating to user management, authentication, authorization, and validation. Service providers will want to use their existing identities, but these will have credentials already that are (hopefully) i...
Nov. 26, 2014 07:00 PM EST Reads: 993
Cultural, regulatory, environmental, political and economic (CREPE) conditions over the past decade are creating cross-industry solution spaces that require processes and technologies from both the Internet of Things (IoT), and Data Management and Analytics (DMA). These solution spaces are evolving into Sensor Analytics Ecosystems (SAE) that represent significant new opportunities for organizations of all types. Public Utilities throughout the world, providing electricity, natural gas and water, are pursuing SmartGrid initiatives that represent one of the more mature examples of SAE. We have s...
Nov. 26, 2014 06:00 PM EST Reads: 997
"Matrix is an ambitious open standard and implementation that's set up to break down the fragmentation problems that exist in IP messaging and VoIP communication," explained John Woolf, Technical Evangelist at Matrix, in this SYS-CON.tv interview at @ThingsExpo, held Nov 4–6, 2014, at the Santa Clara Convention Center in Santa Clara, CA.
Nov. 26, 2014 05:45 PM EST Reads: 937
The Internet of Things will greatly expand the opportunities for data collection and new business models driven off of that data. In her session at @ThingsExpo, Esmeralda Swartz, CMO of MetraTech, discussed how for this to be effective you not only need to have infrastructure and operational models capable of utilizing this new phenomenon, but increasingly service providers will need to convince a skeptical public to participate. Get ready to show them the money!
Nov. 26, 2014 04:00 PM EST Reads: 1,033
One of the biggest challenges when developing connected devices is identifying user value and delivering it through successful user experiences. In his session at Internet of @ThingsExpo, Mike Kuniavsky, Principal Scientist, Innovation Services at PARC, described an IoT-specific approach to user experience design that combines approaches from interaction design, industrial design and service design to create experiences that go beyond simple connected gadgets to create lasting, multi-device experiences grounded in people's real needs and desires.
Nov. 26, 2014 03:45 PM EST Reads: 996
P2P RTC will impact the landscape of communications, shifting from traditional telephony style communications models to OTT (Over-The-Top) cloud assisted & PaaS (Platform as a Service) communication services. The P2P shift will impact many areas of our lives, from mobile communication, human interactive web services, RTC and telephony infrastructure, user federation, security and privacy implications, business costs, and scalability. In his session at @ThingsExpo, Robin Raymond, Chief Architect at Hookflash, will walk through the shifting landscape of traditional telephone and voice services ...
Nov. 26, 2014 02:00 PM EST Reads: 1,474
Scott Jenson leads a project called The Physical Web within the Chrome team at Google. Project members are working to take the scalability and openness of the web and use it to talk to the exponentially exploding range of smart devices. Nearly every company today working on the IoT comes up with the same basic solution: use my server and you'll be fine. But if we really believe there will be trillions of these devices, that just can't scale. We need a system that is open a scalable and by using the URL as a basic building block, we open this up and get the same resilience that the web enjoys.
Nov. 25, 2014 09:30 PM EST Reads: 1,231
The Internet of Things is tied together with a thin strand that is known as time. Coincidentally, at the core of nearly all data analytics is a timestamp. When working with time series data there are a few core principles that everyone should consider, especially across datasets where time is the common boundary. In his session at Internet of @ThingsExpo, Jim Scott, Director of Enterprise Strategy & Architecture at MapR Technologies, discussed single-value, geo-spatial, and log time series data. By focusing on enterprise applications and the data center, he will use OpenTSDB as an example t...
Nov. 25, 2014 09:30 PM EST Reads: 1,282
The Domain Name Service (DNS) is one of the most important components in networking infrastructure, enabling users and services to access applications by translating URLs (names) into IP addresses (numbers). Because every icon and URL and all embedded content on a website requires a DNS lookup loading complex sites necessitates hundreds of DNS queries. In addition, as more internet-enabled ‘Things' get connected, people will rely on DNS to name and find their fridges, toasters and toilets. According to a recent IDG Research Services Survey this rate of traffic will only grow. What's driving t...
Nov. 25, 2014 07:00 PM EST Reads: 1,320
Enthusiasm for the Internet of Things has reached an all-time high. In 2013 alone, venture capitalists spent more than $1 billion dollars investing in the IoT space. With "smart" appliances and devices, IoT covers wearable smart devices, cloud services to hardware companies. Nest, a Google company, detects temperatures inside homes and automatically adjusts it by tracking its user's habit. These technologies are quickly developing and with it come challenges such as bridging infrastructure gaps, abiding by privacy concerns and making the concept a reality. These challenges can't be addressed w...
Nov. 25, 2014 04:30 PM EST Reads: 1,325
Explosive growth in connected devices. Enormous amounts of data for collection and analysis. Critical use of data for split-second decision making and actionable information. All three are factors in making the Internet of Things a reality. Yet, any one factor would have an IT organization pondering its infrastructure strategy. How should your organization enhance its IT framework to enable an Internet of Things implementation? In his session at Internet of @ThingsExpo, James Kirkland, Chief Architect for the Internet of Things and Intelligent Systems at Red Hat, described how to revolutioniz...
Nov. 24, 2014 07:00 PM EST Reads: 1,630
Bit6 today issued a challenge to the technology community implementing Web Real Time Communication (WebRTC). To leap beyond WebRTC’s significant limitations and fully leverage its underlying value to accelerate innovation, application developers need to consider the entire communications ecosystem.
Nov. 24, 2014 12:00 PM EST Reads: 1,516
The definition of IoT is not new, in fact it’s been around for over a decade. What has changed is the public's awareness that the technology we use on a daily basis has caught up on the vision of an always on, always connected world. If you look into the details of what comprises the IoT, you’ll see that it includes everything from cloud computing, Big Data analytics, “Things,” Web communication, applications, network, storage, etc. It is essentially including everything connected online from hardware to software, or as we like to say, it’s an Internet of many different things. The difference ...
Nov. 24, 2014 11:00 AM EST Reads: 1,656
Cloud Expo 2014 TV commercials will feature @ThingsExpo, which was launched in June, 2014 at New York City's Javits Center as the largest 'Internet of Things' event in the world.
Nov. 24, 2014 09:00 AM EST Reads: 1,672
SYS-CON Events announced today that Windstream, a leading provider of advanced network and cloud communications, has been named “Silver Sponsor” of SYS-CON's 16th International Cloud Expo®, which will take place on June 9–11, 2015, at the Javits Center in New York, NY. Windstream (Nasdaq: WIN), a FORTUNE 500 and S&P 500 company, is a leading provider of advanced network communications, including cloud computing and managed services, to businesses nationwide. The company also offers broadband, phone and digital TV services to consumers primarily in rural areas.
Nov. 23, 2014 07:30 PM EST Reads: 1,838
"There is a natural synchronization between the business models, the IoT is there to support ,” explained Brendan O'Brien, Co-founder and Chief Architect of Aria Systems, in this SYS-CON.tv interview at the 15th International Cloud Expo®, held Nov 4–6, 2014, at the Santa Clara Convention Center in Santa Clara, CA.
Nov. 23, 2014 12:00 PM EST Reads: 1,790
The major cloud platforms defy a simple, side-by-side analysis. Each of the major IaaS public-cloud platforms offers their own unique strengths and functionality. Options for on-site private cloud are diverse as well, and must be designed and deployed while taking existing legacy architecture and infrastructure into account. Then the reality is that most enterprises are embarking on a hybrid cloud strategy and programs. In this Power Panel at 15th Cloud Expo (http://www.CloudComputingExpo.com), moderated by Ashar Baig, Research Director, Cloud, at Gigaom Research, Nate Gordon, Director of T...
Nov. 23, 2014 07:45 AM EST Reads: 1,820