Archive
Recent Work on Unit Conversion
My first thought about this project was “boring, but at least it’s a payday.” This application allows students to practice converting across different types of units on actual problems. In terms of interactivity, it’s pretty much dragging rectangular tiles with a numerator and denominator into slots inside a work area. Yes, I’m fading off to sleep as I write
A screenshot of the basic layout is shown below.
Standard tiles are fixed-width and defined in XML so that the tile set for a conversion category can be easily changed (and it was changed multiple times during development).
<category name="Distance"> <metric> <tile id="Distance0" > <numerator value="1000" useCommas="false">meters</numerator> <denominator value="1" useCommas="false">kilometer</denominator> </tile> . . .
which brings us to the interesting part of the application – the text formatting. I worked within the framework used by this client and all UI text components are based on Flash TextFields. Each numerator and denominator has a value and units. Units are written out as text strings, however, units may have singular, plural, and abbreviated forms. The rules for formatting values are comma-formatted unless otherwise specified and scientific notation is used if the number is outside a pre-specified range. The number of displayed digits in scientific notation is also variable. Powers are handled with a superscript font. I had to test if an exponent was applied in the formatting to vertically adjust text placement.
Unit text is auto-converted to an abbreviation if the text is to wide to fit inside the tile. The XML unit type is the preferred formatting, but only if it fits.
The objective of the lesson is to convert the starting units to the requested units using the minimum number of tiles. No more than three tiles may be dragged into the work area and each problem can be solved using no more than three tiles. Tiles may be flipped, which adjusts the numerator and denominator; however, tiles are restored to their original (XML) form when moved back into the work area. When a tile is released outside the work area, it automatically jumps to the nearest open slot (left-to-right).
As tiles are dragged into position, the program checks if any units cancel. Cancellation must take into account any combination of singular, plural, or abbreviated unit.
This is where it gets fun. The program is supposed to draw a red, diagonal strike-through mark across the unit when cancelation is detected. Again, this has to work for any combination of singular, plural, or abbreviated unit, so the drawing is completely programmatic.
The other interesting text-processing aspect of units is that units must be gathered into like form with a single power in the event there is no cancellation. There are also rules for formatting the answer that vary from the work-area tiles, such as rounding to the nearest 0.001 where the rounding value is arbitrary. An example is shown below.
In the denominator, the singular unit, ‘cubic centimeter’ is combined with the abbreviated unit ‘cm^3′ to create a new unit cm^6. This processing is done by a gathering pass where all units are broken down into a ‘fundamental’ unit and exponent. All like units are gathered and the exponents processed to produce the output.
Currently, there is no cancellation in this step unless there is an exact unit match, i.e. cm in the denominator does not cancel cm^4 in the numerator. The goal is to make it easier for the student to see the unit collections across tiles so that they can quickly decide which tiles to move back to the work area.
The text and dynamic drawing aspects of this project proved to be quite interesting. The next time I think someone is presenting me with a boring project, I’ll know to think again
Image Painting in Freehand Drawing Library
A bonus project is going out to all Freehand Drawing Library beta users this morning. Currently, the library contains one fixed-width stroke with three drawing engines and three line decorators. One question arose about how to create different strokes and the role of engines within the architecture. I also received a comment about an iPad drawing app. that allowed people to ‘stamp’ or ‘paint’ smooth strokes with images.
Having an artist create any variety of cool images in Flash is a no-brainer. The question is how to stamp that image repeatedly along a smooth stroke. The answer provides a perfect illustration of stroke creation in the Freehand Drawing Library. A stroke is designed based on certain desired characteristics, in this case the ability to distribute images along a smooth path. A stroke engine (that implements IDrawingEngine) is created to match the general characteristics of a stroke. Not all engines are compatible with all strokes, and that’s fine.
A StampedStroke class (implementing IFreehandDrawable, so it can be used in a Factory) was developed for the desired purpose. A single engine, Stamp, computes the same smoothed stroke coordinates as the SmoothedStroke engine. Since nothing is drawn into any graphics context, the concept of line decorators does not apply. The stroke engine directly instantiates the image symbol and adds it to the display list.
The Stamp engine accepts a single engine parameter, ‘imagestamp’, which is the reference to the symbol created in Flash and exported with a base class that extends MovieClip. Using the stroke is as simple as instantiation,
private var __stroke:StampedStroke = new StampedStroke();
private var __data:StrokeDataVO = new StrokeDataVO();
Make sure the stroke engine and symbol are compiled into the SWF,
import net.algorithmist.freehand.StampedStroke;
import net.algorithmist.freehand.symbols.Starburst;
private static const STAMP_ENGINE:Class = Stamp;
private static const STAR_CLASS:Class = Starburst;
Then, inject stroke engine and assign engine parameters,
__data.drawingEngine = “net.algorithmist.freehand.engine.Stamp”;
__data.engineParams = {imagestamp:”net.algorithmist.freehand.symbols.Starburst”};
Assign the data provider for the stroke,
__stroke.data = __data;
Draw, and have fun. The Stamp engine contains a back door to animating the stroke while it’s being drawn. I may create an online example since it’s pretty cool
The library is currently in the final beta phase before RC1. Because of all the new capability, I’ve opened up several beta slots. There is a small, three-figure license fee, which is a one-time cost. All beta testers get free upgrades for life!
Please contact me at theAlgorithmist [at] gmail [dot] com if interested.
Recent Work Measuring Volume
Anyone who has ever played with a chemistry set should enjoy the description of this project
This learning application teaches students how to measure the volume of regular and irregular objects by their effect on water level in a container.
The application begins in an exploration mode with a layout consisting of a work area and a cabinet containing objects to measure, some containers, and a few tools.
Water may be added to a container from the faucet, which pours at three different rates depending on the slider position. All water levels and animation were drawn programmatically. After adding water, the student may drop an object into a container. Objects may be ‘added’ to empty containers as well. If any part of the object overlaps a container, it is automatically added to the container. In addition to collision detection of irregular objects, a general-purpose animation manager was written for this project. It controlled the animation of objects dropping into containers and setting of a ‘critical’ level, which was used to dispatch an event, from which the rise of the container’s water level was choreographed. This allows the water level to animate in a reasonable manner and be timed to correspond with the object reaching the water level.
Water level rises in a physically realistic manner in that all objects have a mathematical model; box, cylinder, or spherical. Depending on the container and object properties, water in a container may not rise by the volume of the object. For box and cylinder models, computing the water level rise is straightforward. For spherical models, roots of a cubic polynomial must be computed. I added a cubic root finder to this client’s math library. Fortunately, the physics of the problem result in only one root, so resolving multiple roots in an interval was not necessary.
Objects are stacked behind containers by default and when the student moves a container with an object ‘inside’ it, the object moves as well. However, if the student clicks such that the mouse is over the object, the object is moved instead. This is indicated by a glow filter to inform the student they are about to move the object instead of the container.
Layering, however, is not static. If an object is released in such a manner that it does not fall into a container, it is immediately layered in front of all containers. If the same object is later dropped into another container, it is layered behind all containers.
Collision detection includes not only container-object collisions, but detecting when an object is positioned so that it will drop into a container and when a container is in ‘pouring position’ above another container. Container pouring represented the most intricate part of this application.
Two models are involved in pouring, both of which were supplied by the science curricula manager responsible for this application. The first involves computing the pouring angle as a function of the horizontal position of each container’s spout. Given a pouring angle, the second model determines how the ‘side view’ of water in the pouring container is drawn and how much water leaves the container.
This water does not immediately transfer into the destination container. If water spills from a container in the drag handler, a Timer is initiated whose handler transfers water from a virtual ‘in buffer’ to the destination container according to a pouring constant whose value is container-dependent. This constant allows certain visual and interactive constraints (such as water not pouring in too fast or too slow into certain containers) to be met. Adjustment of the water level in the destination container is physically accurate in the presence of contained objects.
In addition to pouring into containers, students may pour water into the sink, which is treated as a faux container for just that purpose.
Overflow from containers is allowed. Certain containers are allowed to overflow into other containers, as shown below.
Three tools are provided, a Ruler (for measuring object dimensions), an eyedropper (for extraction and addition of tiny amounts of water), and a magnifying glass for measuring the meniscus of water in a graduated cylinder. The latter is dynamically drawn using a quadratic Bezier, according to properties assigned by the science curricula manager.
The meniscus is shown whenever a specified interior section of the lens is over the actual meniscus in a graduated cylinder. This test is performed inside the magnifying glass handler using a highly optimized circle-rectangle collision test. The magnifying glass and containers may establish a two-way connection (think of it as two-way binding) so that if water is added to a graduated cylinder, the magnified meniscus view is dynamically redrawn until the meniscus is ‘out of view’ of the lens.
In addition to the exploration view, the application also contains a test or practice view.
Each problem presents students with a selected number of objects, tools, and containers, sufficient to answer the question. Answers are deemed correct if they lie within a specified tolerance. To create a virtually limitless number of questions from a small base, initial volumes and object parameters may be randomized in the question XML. One example problem is
<question type="answer" number="9" category="all" target="Prism" textBox="true" > <questionText> <![CDATA[To the nearest 0.1 cm <span class='sup'><font size = '+4'>3</font></span>, what is the volume of this rectangular prism?]]> </questionText> <textBox> <![CDATA[cm <span class='sup'><font size = '+4'>3</font></span>]]> </textBox> <answer tolerance="0.1" /> <containers /> <objects> <object id="Prism" x="330" y="330"> <length> <generate>3.9 + 0.3*rnd()</generate> </length> <width> <generate>2.4+ 0.3*rnd()</generate> </width> <height> <generate>7.3 + 0.3*rnd()</generate> </height> </object> </objects> <tools> <tool id="ruler" x="460" y="300" /> </tools> </question>
Whenever a <generate> node is encountered, the parser sends the node’s contents to a specialized method that randomizes a value and generates the numerical value of the node. That value is either in-lined into question text or used to calculate object volume.
So, each time the student practices in this view, they receive a the same set of questions with differing values. The code is very efficient in the sense that the same base class for container-object interaction is used to create the two Views. The hierarchy for lab items is DraggableItem -> LabItem -> Lab Object -> LabContainer.
I suppose you can see why I’ve been so busy for the last couple months
Going to take a few days off now before returning to work on the Freehand Drawing Library.
Merry Christmas and best wishes for 2012 to all readers.
Function Graphing Update Part II
I’ve been very quiet over the last few months, and for good reason. Just finished a gig involving two pretty complex learning applications for physical science. I worked on one as a primary developer, and the function graphing engine I authored was used in another. This is the first of a couple posts summarizing the work before returning to development of the Freehand Drawing Library.
The prior update on the function graphing engine was summarized in this post. This particular learning application involves chemical reactions and equilibrium. A simulation is started in one tab, as shown below.
Depending on the simulation length, a substantial number of molecules may interact in a single time step. Clicking on the Graph tab shows a real-time line plot of the state of various reactions.
The x-axis is time steps and the programmer plots the most recent N steps.
A new addition to the graphing engine is the ability to adjust x- and y-axis bounds and tic marks independently. This provides highly customizable zoom capability.
The graph may be panned by dragging, and panning is setup in XML to be restricted to the first quadrant.
This was a very interesting project both because I enjoyed working with the other application developer and to see a cool use of the function graphing engine.
Recent Work: Upgrades to Function Graphing Engine
I wrote a class library for function graphing and exploration (with several complex, interactive features) years ago that uses XML for most of the graphing setup. The library dealt with functions defined by a modest number of parameters whose values may change, but the basic functional representation is immutable.
A student might explore x2 + 3x + 2 over a variety of intervals, or may even study ax2 + bx + c, where the constants a, b, and c are interactively varied. The function is still defined, in advance, by a small, finite number of parameters.
My client recently wished to use this engine to explore functions that arise from physical simulations over time. The ‘function’ is not mathematically defined by a formula. Instead, its values are sampled over time. Data points are plotted either separately, or connected by lines. Two new low-level functions, ScatterPlot and LinePlot were introduced into the defined functions library and new methods were added to the function graphing class to allow data that ‘defines’ a function to be updated at runtime. New methods to adjust the graph range and tic increments were also added.
The function graphing engine now supports panning restrictions by quadrant. Many physical simulations are sampled over time intervals, so the graph x-coordinate is a time sample (always greater than or equal to zero). For simulations whose y-axis values are positive, restricting graph panning to the first quadrant is desirable. One or two-quadrant combination panning restrictions are now allowed in the function graph XML.
<learningObject id=”simulationGraph” class=”display.graphing.functions.FunctionPlot” x=”35″ y=”40″ width=”350″ height=”280″ display=”f1,f2,f3″ pannable=”true” restrictPan=”quadrant:1″ >
Here’s a screenshot of the engine in action,
The modifications have been quite interesting, but would have been far more difficult without the extreme level of internal and external documentation generated for this complex class library. Over two years went by between modifications. So, think about the next person that comes along after your code is written.
It might be you
TinyTLF 2 Explorer App
Paul created a cool demo to explore some of the new features in TinyTLF V2.0 (still in beta). The circular region demo (yes, we can do the equivalent of CSS Regions right now in Flash) has been expanded.
Check out the blog post here and enjoy!
Update: For those who have asked, a new version of the demo with text constrained by spline boundaries is in the works, but scheduled for after the V2 formal release.
Some Recent Work with TinyTLF
I’ve been extremely busy with a gig the last couple months, so posts have been sparse. This is a quick preview of some work with Paul Taylor’s TinyTLF – http://www.tinytlf.org. Paul and I have collaborated in the past on spline-constained text layout and dynamic scrolling with quad. Bezier splines. While I’ve been keeping up with progress on with TinyTLF, this is my first serious application of the library.
The problem is to render interactive ‘word selectors’ in-line with text, provided in html format. An example input is of the form,
<passage><p>Sarah’s <word>father</word> had died in 1797, two years earlier. Life was difficult with him gone, but the family had learned to <word>adapt</word>. Sarah found that she had to support the family with her daily hard work.</p><p>The family’s main <word>product</word> was cattle, but it also raised chickens—and Sarah had been put in charge of both types of animal. Father had worked hard at <word>farming</word> and building furniture, but that business was <word>defunct</word> now that he was gone. Together, the family survived without him due to their courage, tenacity, and <word>strength</word> of character.</p></passage>
Some passages may contain <b> or <i> tags as well. Everywhere a <word> tag is present, an interactive word selector must be rendered in-line with the text. TinyTLF is used to render the text and the word selectors are rendered by a custom TextBlock factory assigned to the TinyTLF text engine. The factory and the word selectors implement specified interfaces (IWordSelectorBlockFactory and IWordSelector). An event is dispatched when the word selectors are added to the stage, which allows the skinnable component controlling passage display to obtain references to the created IWordSelector.
TinyTLF allows the text to be easily styled by assigning styles, either through an external style sheet or constructed from Flex style properties assigned to the passage display class (the technique I use in this app). The rendered result is shown below after some interaction with the word selectors (the same synthetic data is used across all test passages, so the concept of correct vs. incorrect selection is meaningless in this example).
The really cool thing about programming the skinnable component to a set of interfaces and not specific implementations is the ability to quickly create new block factories and selector implementations. This was actually used to switch out rectangular 2D selectors with Actionscript 3D rectangular boxes.
After this gig is finished, I plan to become a contributor to TinyTLF and hope to create some cool examples for public consumption as well as advance the use of splines in TinyTLF layout.
Path Arc-Length Parameterization Preview I
One of my favorite background projects at this time is arc-length parameterization of general paths. Think of a path informally as an ordered collection of planar, parametric curves that may be both spatially discontinuous and discontinuous in first derivative at the end of one curve and the beginning of another curve. Each curve in the path is called a segment and segments may degenerate into lines or points.
One may wonder if cartesian curves, i.e. y = f(x), x in [a,b], are allowable as path segments if all segments are parametric, i.e. x=x(t), y=y(t), t in [0,1]. We can reparameterize the cartesian curve as x(t) = (1-t)a + tb for t in [0,1] and y(t) = f( x(t) ). So, it is acceptable in the future to have natural cubic splines comprise path segments. Can any programmers spot an Adapter pattern here?
The problem in this development is an efficient strategy for the approximate arc-length parameterization of the entire path. In other words, a query for the x-coordinate of the path at a parameter 0.5 should return the x-coordinate of the path segment that is ‘close’ to halfway along the entire path length.
The difficulty lies in the fact that the individual segments (other than lines or points) are not naturally arc-length parameterized. Aside from creating complex, higher-order curves that have the necessary parameterization embedded in the curve construction, the classic efficient solution is to interpolate natural parameter as a function of normalized arc length (i.e. fraction of total length in [0,1]). This yields a model, t = M(s), where both t and s are in [0,1].
The re-parameterization problem consists of finding M for each segment in the total path. Each segment comprises some interval of normalized arc length, i.e. [s0, s1]. Given an input value, s, in [0,1], the Path first determines which segment ‘owns’ that normalized arc length. The segment evaluates its local model to return a natural parameter, t, corresponding to the approximate normalized arc length. The segment is then evaluated in its natural form to return the requested coordinate values.
Because of the wide variety of potential segments, a key to efficient implementation is the concept of reducibility. In other words, each segment must be efficiently approximated as a sequence of simpler segments. Then, we can use one model for each of the ‘atomic’ elements of each segment.
A linear interpolation model sounds reasonable, at least in terms of efficient evaluation. Certainly, any curve may be reduced to a number of small segments over which the normalized arc length as a function of natural parameter is near-linear. The problem is the large number of required subdivisions.
The current work uses a quadratic Bezier as an atomic element. I’ve already illustrated with Degrafa that a wide variety of both cartesian and parametric splines can be reasonably approximated as a sequence of quadratic Beziers. Subdivision of cubic Beziers into sequences of quads is a well-known process.
By reducing all segments other than lines and points to sequences of quadratic Beziers, the re-parameterization problem reduces to that of modeling natural parameter as a function of normalized arc length for a quad. Bezier. It is computationally simple to subdivide a quad. Bezier into a sequence of smaller quad. Beziers. As the number of subdivisions increases, it is reasonable to expect the quad. sequence to ‘flatten’ and eventually approach straight lines. While this approach is suitable for fitting a linear model, it has the disadvantage of producing a very large number of sub-segments. Each subdivision sweep involves fitting and testing a model, so linearization is not an efficient approach.
The current work uses a quadratic model and a more intelligent procedure for subdividing the original quad. Bezier. That process is based on curvature as curvature vs. arc-length is a natural means for describing the shape of a curve. This procedure only fits a quadratic model if the subdivided segment first passes a simple curvature-based test. Subdivision proceeds only if the model fails a relative error test.
In addition to producing much fewer atomic segments for the model, this approach has the advantage of allowing the geometry of the original quad. Bezier to dictate the number of interpolation points. This avoids oversampling for small, flatter segments and undersampling for long segments with large curvature.
I’m currently working on the model for a single, quad. Bezier segment and the structure of the class library. The screen shot below illustrates a sample unit test.
This is just a query of coordinates at normalized arc length 0, 0.5, and 1. The boundary tests are important as the above quad. Bezier is itself subdivided into ten smaller quadratic Beziers. This is far less than the nearly 30 samples I would use for linear interpolation and even with the number of samples for a crude approach to cubic spline interpolation. The latter is very accurate, but very expensive. So, I’m very pleased with this first result although a great deal of additional testing is required before moving onto more complex segments and paths.
The code itself is built entirely to interfaces, not specific implementations. This allows new segments to be quickly inserted into paths and application-specific versions of paths to be created without modifying the code that uses a path. In the current test code, the following interfaces and factories are imported,
import path.SegmentFactory;
import path.PathFactory;
import path.IPath;
import path.IPathSegment;
The two relevant class variables are
private var __path:IPath;
private var __segment:IPathSegment;
The general approach is to create an IPath instance using PathFactory, create segments using SegmentFactory, add those segments to the path, then manipulate the path.
__segment = SegmentFactory.createSegment(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
__path = PathFactory.createPath();
__path.addSegment(__segment);
Currently, there is a default Path class that implements IPath. In the event a programmer needs to modify that functionality, the PathFactory may be modified to return a new IPath implementation. The interface supports getParam() and setParam() methods to allow for access and mutation of arbitrary parameters. The factory constructor supports variable arguments, so it is possible to create a wide variety of IPath implementations without modifying the core application code that uses the path.
The SegmentFactory functions in a similar manner. The first variable arg is an optional String. If that argument is a String, it is treated as the fully qualified class name of a Class that implements IPathSegment. The instance is constructed using the remaining parameters. This allows splines, for example, to be quickly constructed and added to paths without worrying about the specific implementation of each spline.
That’s it for the first preview. Unfortunately, I have to put this project on the back burner once again since I’ve picked up a couple short-term projects. I’ll post more code snippets and results as time allows in the future.
Recent Work XML Map System
This is a brief overview of a project I’ve been working on for an Agency client. This client does a lot of work with interactive applications involving navigation between ‘views’ and ‘frames’ of individual views. Sometimes, the views correspond to geographic maps, although the images are highly artist-stylized (otherwise we could just use Google/ESRI). In some applications, the views might correspond to a floor plan or concert hall. Each new view represents a different snapshot (revealing more detail) of some larger perspective. We loosely use the term ‘map’ to refer to each view, although programmatically, a view is nothing more than an image. Frames of a view correspond to rectangular regions having the same aspect ratio as the main ‘map’ window. Views may have interactive ‘hotspots’, clickable ‘icons’, and animated overlays associated with them in addition to arbitrary framings. If map projection information is available for a view, icons may be geo-coded.
Instead of developing each such application from scratch, the client wanted a class library, Flash ‘template’ and XML data structure to help organize each application into a common structure. This provides numerous benefits in addition to code re-use. Decoupling visual assets from the primary application facilitates easy distribution of design/development workflow among multiple people. Structuring view/frame layout in XML allows non-coders to make simple changes to the application without touching code. The system employs a template .FLA (this agency works only with Flash) and base Document class that encourages commonality among all applications using this ‘map system.’ This makes it very easy for one person to learn the application structure and quickly help on another application without having to deconstruct another person’s code and decipher library assets. The map system employs an internal transition engine that is programmed to an interface, not any specific implementation. This allows transitions to be coded once and then re-used by simply including the transition in the XML and linking it to a view transition by id. Artists may experiment with different view transitions and parameters simply by editing XML. Framing and frame transitions are an interesting exercise in analytic geometry. These are handled internal to the system by a general-purpose zooming engine.
The template .FLA allows a designer to position the ‘map’ application by placing a blank MovieClip on Stage. Since all such applications begin with a common, base template, the clip already resides on Stage for the artist. The widow size is set in XML. The system itself handles internal preloading of the application and all map assets. The lead developer extends the base Document class to override event handlers and add any application-specific logic outside the map. Some of the wiring with regard to hotspots and other interactive elements is handled in XML. Printing is automatically integrated into the system. Either the map or the entire Stage may be printed and print parameters are assigned in XML. Modality is also automatically handled internal to the system and exposed to the application developer via the system API.
Unfortunately, I can’t show the XML or even discuss the code in detail as it’s proprietary, but here are some screen shots shown views/framing, hotspots, and animated overlays.
This application involved a very complex transition between views. Once coded, however, the parameters can be modified in XML and re-used in other map applications simply by including the transition class in the XML and assigning it to a view transition via id. Hotspot interactivity is wired into the main application in XML as each hotspot graphic is associated with a class extending MovieClip inside the system.
This application used only one view with many framings/overlays. Frame transitions are handled internally by the zoom engine. After specifying the framing (rectangle coordinates), the designer sets the transition time in seconds in XML. The application developer initiates the transition from the Document class. A default handler is always overridden to implement app-specific functionality after each transition completes.
Although the term ‘map’ is used to describe the system, the manipulation of views/frames is generic and does not necessarily pertain to geo-coded data. In addition to the numerous coding challenges (including being forced to debug/develop using the Flash IDE), I enjoyed the practical application of analytic geometry in this project. I can only hope that the client is open to extending this system to work with AS only projects in FlashBuilder in the future
AS3 Developer Position in Houston
One of my best clients, an agency in Houston, has an opening for an AS3 developer. If you are available and in the Houston area (locals strongly preferred), then send me an email at theAlgorithmist[at]gmail[dot]com. You should have the following background.
A firm foundation in OOP and event-driven programming with demonstrable expertise developing highly interactive applications in AS3. You should know something about basic design patterns. Flash 10 experience is a bonus. Mobile is an even bigger bonus, but not a requirement. You need to have experience in creating reusable components and helping designers with modest scripting skills create visual elements to be integrated into a larger application. You also need to know how and when to hack something quick to make a deliverable on a short time frame.
Flex/FlashBuilder IDE experience is valuable, but not required (i.e. creating Actionscript projects and integrating visual content created by designers using Flash CS4/CS5). Flex framework experience is a bonus but not required.
Any experience you have using third-party AS3 libraries and extending them to create new functionality is highly desirable. You will be required to work with such libraries developed by me
Don’t send me a resume. Resumes are B.S. documents created for HR people and managers that want buzzwords and other B.S. Show me an online blog/portfolio or something that demonstrates your skills. Then, we’ll talk. I will forward promising candidates onto my client.
I’ve worked with this company for over six years and can vouch that although an agency environment can be challenging, these people are absolutely great to work with. Looking forward to hearing from you.



















