Piccolo2D Patterns
Below, we explain the common programming Paradigms associated with Piccolo2D. This work is based heavily on the work of R. Johnson in his seminal 1992 paper Documenting Frameworks using Patterns and the work of Douglas Kirk in his Patterns for JHotDraw paper. This work merely attempts to adapt the concepts presented there into a format suitable for our Piccolo2D framework.Intro
Pattern 1: Zoomable User Interfaces (ZUI's)
Piccolo2D is a framework for building zoomable user interfaces. The elements of these interfaces can be scaled or animated, and react to user input. The user viewpoint may also be scaled and panned. Interfaces built with Piccolo2D can define your entire application interface, or they can be a small part of a large system.
Figure 1 shows a sequence of frames from a simple zooming interface created using Piccolo2D. This example shows the fundamental aspects of a Piccolo2D application. In this sequence the user is zooming in on a "Hello world!" interface object.
The objects on a piccolo2d canvas are nodes (instances of PNode
), in this case
a PText
node. Nodes are used to represent the discrete components of an interface.
The framework comes with some commonly required nodes (shapes, images, and text) and the
developer has the opportunity to define new ones for their own interfaces.
Figure 1's zooming interaction was created with the help of an event listener (instances of
PInputEventListener
). Event listeners define how the interface reacts to user
input. In this zooming interaction the event listener reacted to mouse input by manipulating
the camera node's view transform to create the zooming effect. Piccolo2D comes with ready-made
event listeners for zooming and panning camera nodes, and dragging nodes on the canvas.
All Piccolo2D interfaces need to be placed in a PCanvas
so that they may be
viewed and interacted with by the user. PCanvas
extends the
javax.swing.JComponent
class in Piccolo2D.Java and the equivalent
System.Windows.Forms.Control
class in Piccolo2D.NET. As a result, piccolo2d
can easily be integrated with both Java Swing and Windows applications. In addition to hosting
Piccolo2D in the application interface, the canvas also maintains a camera and layer node.
Scaling and translating the camera's view transform over time is how zooming and panning is
accomplished. New nodes are normally added to the canvas's layer node.
The interface depicted in figure 1 can be created with the following code:
import edu.umd.cs.piccolo.PCanvas; import edu.umd.cs.piccolo.nodes.PText; import edu.umd.cs.piccolox.PFrame; // The PFrame class is a utility class that creates a new java window // and adds a PCanvas to it. You can override the initialize method and // start building your interface there. public class Piccolo2DExample extends PFrame { public void initialize() { PNode aNode = new PText("Hello World!"); // Add the node to the canvas layer so that it // will be displayed on the screen. getCanvas().getLayer().addChild(aNode); } public static void main(String[] args) { new Piccolo2DExample(); } }
using UMD.HCIL.Piccolo2D; using UMD.HCIL.Piccolo2D.Nodes; using UMD.HCIL.Piccolo2DX; // The PForm class is a utility class that creates a new window // and adds a PCanvas to it. You can override the Initialize method and // start building your interface there. public class Piccolo2DExample : PForm { public override void Initialize() { PText text = new PText("Hello World"); // Add the node to the canvas layer so that it // will be displayed on the screen. Canvas.Layer.AddChild(text); } [STAThread] static void Main() { Application.Run(new Piccolo2DExample()); } }
Note: For simplicity, the C# example does not include the initialization code inserted by Visual Studio.
This creates the default zooming interface. A new text node is added to the surface, and
event handlers for zooming and panning are automatically installed by the
PCanvas
.
- To quickly get started using Piccolo2D, see Usage Patterns for Piccolo2D
- To learn more about the Piccolo2D implementation, see Implementation Patterns for Piccolo2D
- To learn more about common ZUI design patterns, see Design Patterns for ZUI Interfaces
Usage Patterns for Piccolo2D
The Piccolo2D usage patterns are designed to get you up and running with Piccolo2D as quickly as possible. They provide quick "cookbook" explanations of the major things that can be done with Piccolo2D. To gain a better understanding of the Piccolo2D implementation and of its runtime behavior is see Implementation Patterns for Piccolo2D.
- To create nodes see, Creating Nodes
- To create user interactions, see Adding User Interaction
- To create animations, see Activities
Pattern 2: Building and Using Piccolo2D
To use Piccolo2D.Java, you will need to add the appropriate .jar files to your classpath, and to do that you need to know what each .jar file contains, and how to build the framework.
Piccolo2D.Java comes with 4 .jar files:
- piccolo.jar
- This .jar contains the Piccolo2D 2D zooming graphics framework.
- piccolox.jar
- This .jar contains the Piccolo2D extras, and it depends on piccolo.jar
- examples.jar
- This .jar contains simple examples of Piccolo2D, it depends on piccolo.jar and piccolox.jar.
- tests.jar
- This .jar contains unit tests for classes in the Piccolo2D framework, it depends on piccolo.jar and /lib/junit.jar
If you downloaded the compiled distribution of Piccolo2D.Java these .jar files are located for you in "piccolo2d/build/". If you didn't then you will need to build them yourself. This is done by typing 'build all' from within the piccolo2d/ folder.
Piccolo2D.Java also comes with project files for the Eclipse IDE (www.eclipse.org), our favorite development environment for Piccolo2D.Java, and Java in general.
To use Piccolo2D.NET, you will need to add references to the appropriate .dll files in your Visual Studio Project.
Piccolo2D.NET comes with 2 .dll files and 2 .xml files:
- UMD.HCIL.Piccolo2D.dll
- This .dll contains the Piccolo2D.NET 2D zooming graphics framework
- UMD.HCIL.Piccolo2DX.dll
- This .dll contains the Piccolo2D extras, and it depends on UMD.HCIL.Piccolo2D.dll.
- UMD.HCIL.Piccolo2D.xml
- This xml file is necessary to provide intellisense support for UMD.HCIL.Piccolo2D.dll, within the Visual Studio.NET IDE
- UMD.HCIL.Piccolo2DX.xml
- This xml file is necessary to provide intellisense support for UMD.HCIL.Piccolo2DX.dll, within the Visual Studio.NET IDE
You do not need to build either distribution of Piccolo2D.NET. The DLL distribution contains all four of these files at the top level. And, the source distribution contains these files in "Piccolo2D.NET/Bin/".
However, if you modify the source code, then you will need to rebuild the framework. To do this, open "Piccolo2D.NET/Source/Piccolo2D.Net.sln" in Visual Studio.NET. Then, from the "Build" menu select "Rebuild Solution." The new .dll files will be located in "Piccolo2D.NET/Source/Piccolo2D/bin/Debug" and "Piccolo2D.NET/Source/Piccolo2DX/bin/Debug".
Note: For more detailed instructions on setting up Piccolo2D, see the README file that comes with each distribution and the Getting Started tutorial.
Pattern 3: Creating Nodes
There are an infinite variety of nodes that can be included in a zoomable user interface. And, there are several ways to make new nodes for each application.
- Use existing classes
- Piccolo2D is supplied with the default implementations for three kinds of visual nodes:
PText
,PPath
, andPImage
. These may be used ‘as is' in a new application, which saves developers the time and effort required to create such elements themselves, but reduces the knowledge they have about how that figure is implemented. - Subclass existing classes
- Often the default implementations of
PNodes
are ‘almost but not quite' what is required for an interface. In such circumstances, it makes sense to customize the existing node to fit the needs of the interface. This saves time compared with starting from scratch and provides insight into the organization of that node but subclassing will increase the number of classes in the system and carries the responsibility of ensuring that the original intent of that inheritance hierarchy is maintained. - Composition
- An alternative to subclassing, composition can be used in situations where the new functionality required can be created by arranging several preexisting nodes together. A text label could be defined as a rectangle (to define the border) with a text object inside. To facilitate this kind of creation any node may have other child nodes added to them. Adding a text node as a child of the rectangle node could create the text label mentioned above. Composition frees the developer from class details, allows reuse of existing tools and allows dynamic configuration (new arrangements of figures can be constructed while the program runs). But, composition doesn't provide as much freedom as subclassing (it can only compose what is available). And, because of its dynamic nature, it can be difficult to debug problems.
- Custom Node
- The ultimate amount of creative freedom comes from subclassing
PNode
directly.PNode
already provides default behavior for all operations (it is a concrete class). So, it is fairly easy to subclass. Many subclasses will want to override a few key methods:setBounds()
,intersects()
, andpaint()
in Piccolo2D.Java andSetBounds()
,Intersects()
andPaint()
in Piccolo2D.NET.
Each visual interface element in Piccolo2D is a subclass of PNode
. Nodes can be
used directly or customized by sub classing or composition.
The following code defines a new simple (without a border) ellipse node.
public class SimpleEllipseNode extends PNode { private Ellipse2D ellipse; // This nodes uses an internal Ellipse2D to define its shape. public Ellipse2D getEllipse() { if (ellipse == null) ellipse = new Ellipse2D.Double(); return ellipse; } // This method is important to override so that the geometry of // the ellipse stays consistent with the bounds geometry. public boolean setBounds(double x, double y, double width, double height) { if(super.setBounds(x, y, width, height)) { ellipse.setFrame(x, y, width, height); return true; } return false; } // Non rectangular subclasses need to override this method so // that they will be picked correctly and will receive the // correct mouse events. public boolean intersects(Rectangle2D aBounds) { return getEllipse().intersects(aBounds); } // Nodes that override the visual representation of their super // class need to override a paint method. public void paint(PPaintContext aPaintContext) { Graphics2D g2 = aPaintContext.getGraphics(); g2.setPaint(getPaint()); g2.fill(getEllipse()); } }
public class SimpleEllipseNode : PNode { private GraphicsPath ellipse; // This node uses an internal GraphicsPath to define its shape. public GraphicsPath Ellipse { get { if (ellipse == null) ellipse = new GraphicsPath(); return ellipse; } } // This method is important to override so that the geometry of // the ellipse stays consistent with the bounds geometry. public override bool SetBounds(float x, float y, float width, float height) { if(base.SetBounds (x, y, width, height)) { Ellipse.Reset(); Ellipse.AddEllipse(x, y, width, height); return true; } return false; } // Non rectangular subclasses need to override this method so // that they will be picked correctly and will receive the // correct mouse events. public override bool Intersects(RectangleF bounds) { Region ellipseRegion = new Region(Ellipse); return ellipseRegion.IsVisible(bounds); } // Nodes that override the visual representation of their super // class need to override a paint method. protected override void Paint(PPaintContext paintContext) { Graphics g = paintContext.Graphics; if (Brush != null) { g.FillPath(Brush, Ellipse); } } }
- To let the user change the attributes of a node, see Adding user Interaction
- To constrain the layout of a nodes children, see Layout Constraints
Pattern 4: Adding User Interaction
Event listeners represent the modes of interaction between the user and the interface. Piccolo2D comes with event listeners that let the user zoom and pan their viewpoint, and drag nodes in the interface. An important part of designing an interface using Piccolo2D is to design the set of event listeners that will define the user experience.
Once created an event listener must be registered with a node so that it can receive events. Many event handlers register with the camera node so that they get all events that come from the canvas associated with that camera.
This example class creates an event listener that will create rectangle nodes on the canvas's layer when the user presses, drags, and then releases the mouse.
// This event listener works by keeping track of the mouse press // location and the current mouse drag location. It then sizes the new // rectangle around those points. Note: The implementation of this event // handler could be simplified by sub classing PDragSequenceEventHandler. public class RectangleCreationEventHandler extends PBasicInputEventHandler { // The rectangle that is currently getting created. protected PPath rectangle; // The mouse press location for the current pressed, drag, release // sequence. protected Point2D pressPoint; // The current drag location. protected Point2D dragPoint; public void mousePressed(PInputEvent e) { super.mousePressed(e); PLayer layer = ((PCanvas)(e.getComponent())).getLayer(); // Initialize the locations. pressPoint = e.getPosition(); dragPoint = pressPoint; // create a new rectangle and add it to the canvas layer so // that we can see it. rectangle = new PPath(); rectangle.setStroke(new BasicStroke( (float)(1/ e.getCamera().getViewScale()))); layer.addChild(rectangle); // update the rectangle shape. updateRectangle(); } public void mouseDragged(PInputEvent e) { super.mouseDragged(e); // update the drag point location. dragPoint = e.getPosition(); // update the rectangle shape. updateRectangle(); } public void mouseReleased(PInputEvent e) { super.mouseReleased(e); // update the rectangle shape. updateRectangle(); rectangle = null; } public void updateRectangle() { // create a new bounds that contains both the press and // current drag point. PBounds b = new PBounds(); b.add(pressPoint); b.add(dragPoint); // Set the rectangles bounds. rectangle.setPathTo(b); } }
// This event listener works by keeping track of the mouse press // location and the current mouse drag location. It then sizes the new // rectangle around those points. Note: The implementation of this event // handler could be simplified by sub classing PDragSequenceEventHandler. public class RectangleCreationEventHandler : PBasicInputEventHandler { // The rectangle that is currently getting created. protected PPath rectangle; // The mouse press location for the current pressed, drag, release // sequence. protected PointF pressPoint; // The current drag location. protected PointF dragPoint; public override void OnMouseDown(object sender, PInputEventArgs e) { base.OnMouseDown (sender, e); PLayer layer = e.Canvas.Layer; // Initialize the locations. pressPoint = e.Position; dragPoint = pressPoint; // Create a new rectangle and add it to the canvas layer so // that we can see it. rectangle = new PPath(); rectangle.Pen = new Pen(Brushes.Black, (float)(1/ e.Camera.ViewScale)); layer.AddChild(rectangle); // update the rectangle shape. UpdateRectangle(); } public override void OnMouseDrag(object sender, PInputEventArgs e) { base.OnMouseDrag (sender, e); // Update the drag point location. dragPoint = e.Position; // Update the rectangle shape. UpdateRectangle(); } public override void OnMouseUp(object sender, PInputEventArgs e) { base.OnMouseUp (sender, e); // Update the rectangle shape. UpdateRectangle(); rectangle = null; } public void UpdateRectangle() { // Create a new bounds that contains both the press and // current drag point. RectangleF r = RectangleF.Empty; r = PUtil.AddPointToRect(r, pressPoint); r = PUtil.AddPointToRect(r, dragPoint); // Set the rectangles bounds. rectangle.PathReference.Reset(); rectangle.AddRectangle(r.X, r.Y, r.Width, r.Height); } }
The code to register this event listener with the canvas would look like this:
getCanvas().addInputEventListener(new RectangleCreationEventHandler());
Canvas.AddInputEventListener(new RectangleCreationEventHandler());
Note that this event handler reacts to the same events that the zoom and pan event handlers
react to. If they are all active on the canvas at the same time undesired behavior would occur.
Often you will want to remove the default pan and zoom event handlers associated with the
PCanvas
, this can be done as follows:
getCanvas().removeInputEventListener(getCanvas().getZoomEventHandler()); getCanvas().removeInputEventListener(getCanvas().getPanEventHandler());
Canvas.RemoveInputEventListener(Canvas.ZoomEventHandler); Canvas.RemoveInputEventListener(Canvas.PanEventHandler);
In Piccolo2D.NET you can also use the following shortcut:
C#
Canvas.ZoomEventHandler = null; Canvas.PanEventHandler = null;
A general problem when defining global event handlers is making sure that they do not
conflict. The Java PInputEventFilter
class and the C#
PInputEventListener.DoesAcceptEvent()
method can help in this regard.
In Piccolo2D.NET there is another way to handle basic input events. You can connect an event handler method directly to a node in the same way that .NET event handlers can be connected to a control. This allows you to define your event handlers in style consistent with .NET events. For example, the following code prints a message every time the user clicks the green node:
C#
public override void Initialize() { PNode aNode = new PNode(); aNode.SetBounds(0,0, 100, 100); aNode.Brush = Brushes.Green; Canvas.Layer.AddChild(aNode); aNode.MouseDown += new PInputEventHandler(aNode_MouseDown); } protected void aNode_MouseDown(object sender, PInputEventArgs e) { System.Console.WriteLine("Clicked aNode!"); }
For more information about the tradeoffs of each of these approaches see the Defining User Interaction tutorial on the Getting Started page.
- To learn more about coordinate systems, see Coordinate Systems
- To learn more about event dispatch, see Dispatching Events
Pattern 5: Layout Constraints
Often an interface has constraints that must be maintained between a node and its children. For example a node may want to always make its children line up in a row or a node may wish to expand its base size to always fully contain the bounds of its children.
The PNode
class does no automatic layout of its own, but it provides methods
that subclasses can override to perform layout in the appropriate place during the layout
process.. The following is a simple layout node that overrides and lays its children out in a
horizontal row.
PNode layoutNode extends PNode { public void layoutChildren() { double xOffset = 0; double yOffset = 0; Iterator i = getChildrenIterator(); while (i.hasNext()) { PNode each = (PNode) i.next(); each.setOffset(xOffset - each.getX(), yOffset); xOffset += each.getFullBoundsReference().getWidth(); } } }
public class LayoutNode : PNode { public override void LayoutChildren() { float xOffset = 0; float yOffset = 0; PNodeList children = this.ChildrenReference; foreach (PNode each in children) { each.Offset = new PointF(xOffset - each.X, yOffset); xOffset += each.FullBounds.Width; } } }
- For more information on the layout process, see Validating Bounds
- For more information on the "full" term used in fullBounds, see Full Terminology
Pattern 6: Activities
Event handlers let an interface react to a user. Activities are used to give the interface a life of its own through the use of animation and other "scheduled" behaviors.
Activities control some time-dependent aspect of the Piccolo2D system, usually some part of a node. This behavior may be of fixed duration or may continue until some termination condition is met (or perhaps forever). Activities of fixed duration may be defined to consume a fixed amount of time, independent of the frame rate.
This method sets up a flash activity that flashes the given node's color from red to green for 5 seconds.
public void flashNode(final PNode aNode) { PActivity flash = new PActivity(5000) { boolean fRed = true; protected void step(long time) { super.step(time); if (fRed) { aNode.setPaint(Color.red); } else { aNode.setPaint(Color.green); } fRed = !fRed; } }; // Must schedule the activity with the root for it to run. aNode.getRoot().addActivity(flash); }
public void flashNode(PNode aNode) { PActivity flash = new PActivity(5000); flash.ActivityStepped = new ActivitySteppedDelegate(ActivityStepped); // Must schedule the activity with the root for it to run. Canvas.Root.AddActivity(flash); } protected void ActivityStepped(PActivity activity) { if (fRed) { aNode.Brush = Brushes.Red; } else { aNode.Brush = Brushes.Green; } fRed = !fRed; }
Activities are scheduled by the PRoot
until they have completed. Note that for
animation activities you can also use the convenience methods in PNode
:
public PTransformActivity animateToPositionScaleRotation(double x, double y, double scale, double theta, long duration); public PTransformActivity animateToTransform(AffineTransform aDestination, long duration);
public virtual PTransformActivity AnimateToPositionScaleRotation(float x, float y, float scale, float theta, long duration); public virtual PTransformActivity AnimateToMatrix(PMatrix destMatrix, long duration);
Each activity has a start time and a duration, that together determine when an activity
starts stepping and how long it continues to step. The Java PActivity.startAfter()
and the C# PActivity.StartAfter()
methods may be used to sequence an activity so
that it starts right after another has stopped.
- To learn more about activities see, Processing Activities
Pattern 7: Standard Widget Toolkit (SWT) connection
SWT is a new Java toolkit (similar to and replacing Swing) that comes out of the Eclipse IDE project. Piccolo2D.Java was originally designed to work with swing, but now has preliminary SWT support as well. You will most likely use SWT if you are writing Piccolo2D extensions to the Eclipse IDE. See www.eclipse.org for more info on the Eclipse project.
Again SWT support is not complete. We are interested in your feedback and hope it is of use,
but we can not promise future updates. SWT support is provided in the extras package in
edu.umd.cs.piccolox.swt
, and you will find SWT examples in the examples
package. Here is the code for SWT hello world:
Java
public class SWTHelloWorld { public SWTHelloWorld() { super(); } public static void main(String[] args) { Display display = new Display (); Shell shell = open(display); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } public static Shell open(Display display) { final Shell shell = new Shell(display); shell.setLayout(new FillLayout()); PSWTCanvas canvas = new PSWTCanvas(shell,0); PSWTText text = new PSWTText("Hello World"); canvas.getLayer().addChild(text); shell.open(); return shell; } }
Implementation Patterns for Piccolo2D
The Piccolo2D implementation patterns are designed to give a general understanding of how Piccolo2D is implemented and what its runtime behaviors are. This is opposed to the patterns in Usage Patterns For Piccolo2D that are designed to get you using the framework as quickly as possible.
Pattern 8: Piccolo2D Framework Design
You should be familiar with the basic concepts of the Piccolo2D framework design and how they relate to each other to effectively use Piccolo2D.
Piccolo2D is a direct-manipulation graphics framework that supports constructing zoomable interfaces. The framework's design borrows heavily from the designs of both the Jazz and Morphic interface frameworks.
Piccolo2D Class Hierarchy
There are four main classes that define the framework's core:
PNode
(anything that is visible and gets events)PCamera
(a node that looks at other layer nodes, and applies a view transform)PLayer
(a node that can be looked at by a camera)PRoot
(the root of the Piccolo2D display tree)PCanvas
(the host component that letsPNodes
exist in a Java Swing or .NET Windows application. EachPCanvas
is associated with aPCamera
. But all cameras are not necessarily directly associated with aPCanvas
, internal cameras for example are not.)
Piccolo2D Runtime Structure
At runtime these classes form a tree-like structure with the PRoot
situated at
the top. Each PCamera
is normally linked with at least one PLayer
that it looks at through it's view transform. If a camera is associated with a canvas then that
camera's view is displayed on the canvas, and input events from the canvas enter the Piccolo2D
scene graph at that camera's point in the hierarchy.
PNode
Nodes are the central design concept in Piccolo2D. Any object that wants to paint itself on the screen should inherit from the node class. In addition to painting on the screen all nodes may have other "child" nodes added to them. Visual structures are build up by grouping and sub grouping collections of nodes.
Each node also has its own affine transform that is applied before the node is drawn to the screen. This transform can be modified to scale and translate the node. The transform exists directly above the node, but below the node's parent. Thus, translating it will translate the node (and all its descendents) but will not translate the node's parent.
PCamera
Cameras are nodes that have an additional view transform and a collection of layers in
addition to the collection of children that they inherit from PNode
. The view
transform is applied before drawing or picking the layers, but not when drawing or picking the
camera's children. Cameras may (an internal camera might not) also reference a
PCanvas
, and forward repaint events to that canvas. The canvas would then later
ask the camera to draw the damaged region on its surface.
PLayer
Layer nodes are nodes that can be viewed by one or more cameras. They maintain a list of the cameras that are viewing them, and notify these cameras when they are repainted.
PRoot
The PRoot
serves as the topmost node in the Piccolo2D runtime structure; all
other nodes are its direct children or descendents of its children. The PCanvas
communicates with the root node to manage screen updates and to dispatch events to its
children.
PCanvas
The PCanvas
is a JComponent
in Piccolo2D.Java and a
Control
in Piccolo2D.NET. Thus, it is used to view a Piccolo2D scene graph in Java
Swing and .NET Windows applications respectively. The PCanvas
views the scene
graph through a PCamera
. It forwards input events to that camera, and uses that
camera to draw itself. Translating and scaling that camera's view transform is how panning and
zooming are accomplished.
Pattern 9: Full Terminology
Many of PNode's methods work on the composite structure (the node plus all its descendents) of the node. It is helpful to be able to easily distinguish these methods from ones that only work directly on the node and not on its children.
Piccolo2D uses the term "full" to mean a node and its descendants with the node's transform applied. This helps distinguish between methods that work on a single node and those that work on a node together with all of its descendants with the node's transform applied. When traversing the node scene graph to paint or calculate bounds parent nodes generally call the "full" methods of their direct child nodes. For example:
// Returns the bounding box of the given node without the node's // transform applied. aNode.getBounds(); // Returns the bounds of the given node combined with the bounds of // all of the descendants of that node after applying the node's // transform. Descendants need not be contained in the bounds of // their parent, so this full bounds value may be larger than the // bounds, but it will never be smaller. aNode.getFullBounds(); // This will paint just "aNode" and not any of its children. Normally this // method is automatically called from the fullPaint method. aNode.paint(aPaintContext); // This will paint "aNode" together will all of that node's descendents. aNode.fullPaint(aPaintContext);
// Returns the bounding box of the given node without the node's // transform applied. aNode.Bounds; // Returns the bounds of the given node combined with the bounds of // all of the descendants of that node after applying the node's // transform. Descendants need not be contained in the bounds of // their parent, so this full bounds value may be larger than the // bounds, but it will never be smaller. aNode.FullBounds; // This will paint just "aNode" and not any of its children. Normally this // method is automatically called from the FullPaint method. aNode.Paint(aPaintContext); // This will paint "aNode" together will all of that node's descendents. aNode.FullPaint(aPaintContext);
Subclasses should generally not override the "full" methods, since they are implemented in terms of other methods that can be overridden.
Pattern 10: Coordinate Systems
Each node in Piccolo2D has its own transform that it uses to define its own coordinate system. It is essential that you understand coordinate systems, and how to convert from one coordinate system to another when designing a zoomable user interface.
There may be thousands of different coordinate systems in a Piccolo2D interface (a different one for each node), but they can all be organized into three categories:
- Local
- The local coordinate system is specific to a single node. This coordinate system exists directly below that node's transform. The base bounds of a node are kept in this local coordinate system, while the fullBounds of a node are stored in the local coordinate system of the nodes parent. (This means that the full bounds of a node have been transformed up through the node's transform, but are still below the node's parent's transform).
- Global
- The global coordinate system exists above the root node's transform, but below the canvas's view transform. The global coordinate system serves as a common coordinate system that can be used as an intermediate when converting from the local coordinates of one node to that of another node.
- Canvas
- The canvas coordinate system is equal to the coordinate system of the
PCanvas
.
Piccolo2D provides methods that let you easily convert between different coordinate systems.
The PNode
class defines the methods:
- localToGlobal() - Transform up from a node's local coordinate system into the global coordinates..
- globalToLocal() - Transform down from global coordinate system into a node's local coordinates.
- localToParent() - Transform up from a node's local coordinate system into the node's parent's local coordinates.
- parentToLocal() - Transform down from a node's parent's local coordinate system into the node's local coordinates.
- LocalToGlobal() - Transform up from a node's local coordinate system into the global coordinates..
- GlobalToLocal() - Transform down from global coordinate system into a node's local coordinates.
- LocalToParent() - Transform up from a nodes local coordinate system into the node's parent's local coordinates.
- ParentToLocal() - Transform down from a node's parent's local coordinate system into the node's local coordinates.
Here is a typical example of how coordinate systems are used:
// This method connects the centers of two // rectangle nodes with a line node. If you know that two nodes // exist in the same coordinate system then you don't need to make // all these conversions. This example assumes the most general case where // they all exist in different coordinate systems. public void connectRectsWithLine(PPath rect1, PPath rect2, PPath line) { // First get the center of each rectangle in the // local coordinate system of each rectangle. Point2D r1c = rect1.getBounds().getCenter2D(); Point2D r2c = rect2.getBounds().getCenter2D(); // Next convert that center point for each rectangle // into global coordinate system. rect1.localToGlobal(r1c); rect2.localToGlobal(r2c); // Now that the centers are in global coordinates they // can be converted into the local coordinate system // of the line node. line.globalToLocal(r1c); line.globalToLocal(r2c); // Finish by setting the endpoints of the line to // the center points of the rectangles, now that those // center points are in the local coordinate system of the line. line.setPathTo(new Line2D.Double(r1c, r2c)); }
// This method connects the centers of two // rectangle nodes with a line node. If you know that two nodes // exist in the same coordinate system then you don't need to make // all these conversions. This example assumes the most general case where // they all exist in different coordinate systems. public void ConnectRectsWithLine(PPath rect1, PPath rect2, PPath line) { // First get the center of each rectangle in the // local coordinate system of each rectangle. PointF r1c = PUtil.CenterOfRectangle(rect1.Bounds); PointF r2c = PUtil.CenterOfRectangle(rect2.Bounds); // Next convert that center point for each rectangle // into global coordinate system. r1c = rect1.LocalToGlobal(r1c); r2c = rect2.LocalToGlobal(r2c); // Now that the centers are in global coordinates they // can be converted into the local coordinate system // of the line node. r1c = line.GlobalToLocal(r1c); r2c = line.GlobalToLocal(r2c); // Finish by setting the endpoints of the line to // the center points of the rectangles, now that those // center points are in the local coordinate system of the line. line.Reset(); line.AddLine(r1c.X, r1c.Y, r2c.X, r2c.Y); }
Pattern 11: UI Cycle
The root node's UI Cycle is at the center of Piccolo2D's runtime behavior where it drives the processes for processing user input, activities, bounds management, and scheduling repaints.
The PRoot
class is responsible for running the UI Cycle. During each cycle it
performs four actions:
- Process Inputs
- Incoming input events from Swing or .NET are passed to the dispatch manager which will
then send them to the appropriate
PInputEventListeners
. - Process Activities
- All activities that are ready to run are given a chance to do so.
- Validate Bounds
- All invalidated bounds are updated, and bounds caches filled.
- Update Display
- Damage is collected for all areas of the screen that need to be repainted and is then sent to the Swing or .NET repaint manager.
The Piccolo2D UI loop is always driven from the event dispatch thread. A UI cycle is done for each new input event received by the canvas, and for each time the activity timer fires (to support animation).
- To learn more about Piccolo2D and threads, see Threads
- To learn more about dispatching events, see Dispatching Events
- To learn more about processing activities, see Processing Activities
- To learn more about the bounds validation, see Validating Bounds
- To learn more about updating the display, see Updating the Display
Pattern 12: Threads
Piccolo2D is not thread safe and should only be used by a single thread at a time, and that thread will almost always be the event dispatch thread.
If you need to run a computation in another thread you will need to call special methods to
connect the results of your computation back up to the event dispatch thread. In
Piccolo2D.Java, use SwingUtilities.invokeLater()
or
SwingUtilities.invokeAndWait()
. In Piccolo2D.NET, use
Control.BeginInvoke()
and Control.Invoke()
.
Pattern 13: Dispatching Events
Event dispatch is the process through which Piccolo2D directs new events coming from the user to event handlers in the interface.
All event dispatch is managed by the input manager (PInputManager
). Events get
to the dispatch manager by first coming off the Java or .NET event queue, next they are sent to
the canvas (PCanvas
) and the canvas forwards them to the input manager.
The input manager then converts the incoming Java or .NET event to a Piccolo2D event.
In Piccolo2D.Java, a java.awt.InputEvent
is converted into a
PInputEvent
. In Piccolo2D.NET, a System.EventArgs
is converted into a
PInputEventArgs
. Next the input manager sends the Piccolo2D event to the event
listeners of the appropriate nodes. The dispatch manager maintains the following focus
nodes:
- Keyboard Focus
- The node that gets key events sent to it (Usually defined when the mouse is pressed)
- Mouse Over Focus
- The node that the mouse cursor is over. When a node first becomes the current mouse over node it is sent a mouse entered event, and when the mouse leaves it is sent a mouse exited event.
- Mouse Focus
- The mouse focus node is sent mouse pressed, dragged, and released events. When the mouse is pressed the dispatch manager gets the mouse over focus, and makes it the mouse focus node as well. This mouse focus node is sent all events from that mouse pressed, dragged, released sequence. After the release event arrives the dispatch manager sets the mouse focus back to null.
Events are dispatched up the PPickPath
associated with a given focus node, so
they percolate up the pick path until they are consumed or they reach the originating camera
node.
TIP: You can always get a reference to the dispatch manager from a PInputEvent
,
and ask it for the current focus nodes.
Pattern 14: Processing Activities
All scheduled activities are given a chance to run during the UI Cycle.
Activities are used to control some time dependent aspect of the Piccolo2D framework, for example they can be used to animate a node across the screen, or animate the camera's view transform to perform a zoom.
Pattern 15: Validating Bounds
When the geometry of a node changes its bounds caches need to be recomputed and the geometry of other related nodes may also be effected.
Maintaining bounds caches and updating layouts can become very expensive when manipulating a large number of nodes. Because of this Piccolo2D uses a two stage incremental approach to layout management. The two stages consist of a damage stage where damage is recorded in bit flags for each damaged node and an incremental repair stage where the damage is repaired as is needed.
The damage stage begins when some node geometry changes. When this happens the type of damage that occurred is recorded for each node. The are three kinds of damage that can occur:
- bounds invalidated
- This damage is recorded whenever the bounds of a node change.
- full bounds invalidated
- This damage is recorded anytime the fullBoundsCache becomes invalid.
- child bounds invalidated
- This damage is recorded anytime the full bounds of any descendant node is invalidated.
Damage is repaired by PNode's
validateFullBounds method at the end of the UI
cycle. That method does the following things
- If the node's bounds have been invalidated, then validate them.
- If the node's child bounds invalidated flag is set then all of the nodes children are validated.
- Next layout the children. (by default, the layout method of
PNode
does nothing, but layout manager nodes would override it). - If the node's full bounds invalidated flag is set then:
- Record the node's old full bounds
- Compute the node's new full bounds
- If the node's full bounds have change make sure to invalidate the full bounds of the parent node.
- The layout is now up to date, so clear the layout flags.
Pattern 16: Updating the Display
Piccolo2D should paint the screen only when needed, and it should be smart about only painting the portions of the screen that need to be painted.
Display update in Piccolo2D is driven from the UI Cycle, and uses the same damage/repair design that Piccolo2D uses to validate bounds. When a node changes such that it needs to be repainted it invalidates its paint, and invalidates the child paint of all its ancestors. Later (at the end of the UI Cycle) screen damage is collected for all nodes with invalid paint.
Design Patterns for ZUI Interfaces
This section contains a few basic patterns that occur frequently in ZUIs, and describes how they can be implemented with Piccolo2D. To learn more about using Piccolo2D see Usage Patterns For Piccolo2D, and to learn more about the Piccolo2D implementation see Implementation Patterns for Piccolo2D.
Pattern 17: Semantic Zooming
It is useful for an object to change its visual representation based on the scale that it is being viewed at. For example when a document is viewed from far away (at a small scale) in a ZUI it might be best to just show that documents title, but when the view is zoomed in all the documents content should become visible.
To do semantic zooming in Piccolo2D you should override the appropriate paint method, and then choose how the node renders itself based on the scale stored in the paint context parameter. This example creates a new node that will paint its based bounds filled with a blue color when viewed at a scale that is less than one, and with an orange color when the scale is greater than one.
public class SemanticNode extends PNode { public void paint(PPaintContext aPaintContext) { double s = aPaintContext.getScale(); Graphics2D g2 = aPaintContext.getGraphics(); if (s < 1) { g2.setPaint(Color.blue); } else { g2.setPaint(Color.orange); } g2.fill(getBoundsReference()); } }
public class SemanticNode : PNode { protected override void Paint(PPaintContext paintContext) { float s = paintContext.Scale; Graphics g = paintContext.Graphics; if (s < 1) { g.FillRectangle(Brushes.Blue, this.Bounds); } else { g.FillRectangle(Brushes.Orange, this.Bounds); } } }
Pattern 18: Sticky Objects
It is useful for an object to "stick" to a camera, so that its position does not change even when the camera is zoomed and panned.
To do this in Piccolo2D you should add the "sticky node" as a child of the camera. The camera's view transform is only applied to the layer nodes that it is viewing, not to its children. The children are drawn after (on top of) the layer nodes.
This example creates a yellow rectangle with bounds handles and adds it to the camera as a sticky node. A standard rectangle is then added to the main layer. Zooming in and out will change the scale of the standard rectangle but not the sticky one.
public void initialize() { PPath sticky = PPath.createRectangle(0, 0, 50, 50);; sticky.setPaint(Color.YELLOW); sticky.setStroke(null); PBoundsHandle.addBoundsHandlesTo(sticky); getCanvas().getLayer().addChild(PPath.createRectangle(0, 0, 100, 80)); getCanvas().getCamera().addChild(sticky); }
public override void Initialize() { PPath sticky = PPath.CreateRectangle(0, 0, 50, 50);; sticky.Brush = Brushes.Yellow; sticky.Pen = null; PBoundsHandle.AddBoundsHandlesTo(sticky); Canvas.Layer.AddChild(PPath.CreateRectangle(0, 0, 100, 80)); Canvas.Camera.AddChild(sticky); }


Module window
Window library
Functions
| desktop () | Returns the desktop |
| clearDesktop () | Clear the desktop |
| drawBackground (x, y, width, height) | Draw a section of the desktop background. |
| moveWindow (win, targetX, targetY) | Move the given window |
| drawWindow (win) | Draw the given window |
| requestExclusiveContext () | Returns context if the caller can now use the GPU driver freely by temporarily disabling the window manager This could typically be used for games or fullscreen Fushell programs. |
| drawDesktop () | Draw all the windows in the desktop |
| newWindow (width, height[, title]) | Create a new window |
| focus () | Focus the window |
Fields
| title | Title of the window |
Functions
- desktop ()
- Returns the desktop
- clearDesktop ()
- Clear the desktop
- drawBackground (x, y, width, height)
-
Draw a section of the desktop background.
Parameters:
- x int The X position of the background section
- y int The Y position of the background section
- width int The width of the background section
- height int The height of the background section
- moveWindow (win, targetX, targetY)
-
Move the given window
Parameters:
- win
- targetX
- targetY
- drawWindow (win)
-
Draw the given window
Parameters:
- win
- requestExclusiveContext ()
- Returns context if the caller can now use the GPU driver freely by temporarily disabling the window manager This could typically be used for games or fullscreen Fushell programs.
- drawDesktop ()
- Draw all the windows in the desktop
- newWindow (width, height[, title])
-
Create a new window
Parameters:
- width int The width of the new window
- height int The height of the new window
- title string The title of the new window (optional)
Returns:
-
window
The newly created window
- focus ()
- Focus the window


There are two Alignment axis. Lawful and Moral.
| Law Axis |
|---|
Then a search for "Lawful,Neutral,Chaotic" should return: (Alpha Sort used for verification)
| Matching Values |
|---|
| Chaotic |
| Lawful |
| Neutral |
Search for "LAWFUL,neutral,chAotIc" should return: (Alpha Sort used for verification)
Case-Sensitive?: false
| Matching Values |
|---|
| Lawful |


An American businessman took a vacation to a small coastal Mexican village on doctor’s orders. Unable to sleep after an urgent phone call from the office the first morning, he walked out to the pier to clear his head. A small boat with just one fisherman had docked, and inside the boat were several large yellowfin tuna. The American complimented the Mexican on the quality of his fish.
“How long did it take you to catch them?” the American asked.
“Only a little while,” the Mexican replied in surprisingly good English.
“Why don’t you stay out longer and catch more fish?” the American then asked.
“I have enough to support my family and give a few to friends,” the Mexican said as he unloaded them into a basket.
“But… What do you do with the rest of your time?”
The Mexican looked up and smiled. “I sleep late, fish a little, play with my children, take a siesta with my wife, Julia, and stroll into the village each evening, where I sip wine and play guitar with my amigos. I have a full and busy life, señor.”
The American laughed and stood tall. “Sir, I’m a Harvard M.B.A. and can help you.  In no time, you could buy several boats with the increased haul. Eventually, you would have a fleet of fishing boats.”
He continued, “Instead of selling your catch to a middleman, you would sell directly to the consumers, eventually opening your own cannery. You would control the product, processing, and distribution. You would need to leave this small coastal fishing village, of course, and move to Mexico City, then to Los Angeles, and eventually to New York City, where you could run your expanded enterprise with proper management.
The Mexican fisherman asked, “But, señor, how long will all this take?”
To which the American replied, “15-20 years, 25 tops.”
“But what then, señor?”
The American laughed and said, “That’s the best part. When the time is right, you would announce an IPO and sell your company stock to the public and become very rich. You would make millions.”
“Millions señor? Then what?”
“Then you would retire and move to a small coastal fishing village, where you would sleep late, fish a little, play with your kids, take a siesta with your wife, and stroll in to the village in the evenings where you could sip wine and play your guitar with your amigos.”
Adapted from the “Anekdote zur Senkung der Arbeitsmoral” by Heinrich Böll
An influential German write and Nobel Prize for Literature in 1972.


The lightdm package contains a lightweight display manager based upon GTK.
This package is known to build and work properly using an LFS-9.1 platform.
Download (HTTP): https://github.com/CanonicalLtd/lightdm/releases/download/1.30.0/lightdm-1.30.0.tar.xz
Download MD5 sum: c566ea595f2b81e68684be9f8dbcbb42
Download size: 500 KB
Estimated disk space required: 21 MB
Estimated build time: 0.2 SBU
The greeter is a program to present a graphical login screen. There are several alternative greeters, but the gtk+ package is the reference implementation. For a list of other greeters, see https://en.wikipedia.org/wiki/LightDM.
Download (HTTP): https://launchpad.net/lightdm-gtk-greeter/2.0/2.0.6/+download/lightdm-gtk-greeter-2.0.6.tar.gz
Download MD5 sum: 36dc961f14cc3b0baef3ddb1c494eb16
Download size: 564 KB
Estimated disk space required: 5.0 MB
Estimated build time: less than 0.1 SBU
Exo-0.12.11 (for the greeter), libgcrypt-1.8.5, itstool-2.0.6, Linux-PAM-1.3.1, and PCRE-8.44
gobject-introspection-1.64.0, libxklavier-5.4, and Vala-0.48.2
AccountsService-0.6.55 (run time), at-spi2-core-2.36.0, GTK-Doc-1.32, Qt-5.14.1, libido, and libindicator
User Notes: http://wiki.linuxfromscratch.org/blfs/wiki/lightdm
First, create a dedicated user and group to take control of the
lightdm daemon after
it is started. Issue the following commands as the root
user:
groupadd -g 65 lightdm && useradd -c "Lightdm Daemon" \ -d /var/lib/lightdm \ -u 65 -g lightdm \ -s /bin/false lightdm
Then change the Linux-PAM configuration files so that elogind is used:
sed -i s/systemd/elogind/ data/pam/*
Install lightdm by running the following commands:
./configure \ --prefix=/usr \ --libexecdir=/usr/lib/lightdm \ --localstatedir=/var \ --sbindir=/usr/bin \ --sysconfdir=/etc \ --disable-static \ --disable-tests \ --with-greeter-user=lightdm \ --with-greeter-session=lightdm-gtk-greeter \ --docdir=/usr/share/doc/lightdm-1.30.0 && make
This package does not come with a test suite.
Now, as the root
user:
make install && cp tests/src/lightdm-session /usr/bin && sed -i '1 s/sh/bash --login/' /usr/bin/lightdm-session && rm -rf /etc/init && install -v -dm755 -o lightdm -g lightdm /var/lib/lightdm && install -v -dm755 -o lightdm -g lightdm /var/lib/lightdm-data && install -v -dm755 -o lightdm -g lightdm /var/cache/lightdm && install -v -dm770 -o lightdm -g lightdm /var/log/lightdm
Now build the greeter:
tar -xf ../lightdm-gtk-greeter-2.0.6.tar.gz && cd lightdm-gtk-greeter-2.0.6 && ./configure \ --prefix=/usr \ --libexecdir=/usr/lib/lightdm \ --sbindir=/usr/bin \ --sysconfdir=/etc \ --with-libxklavier \ --enable-kill-on-sigterm \ --disable-libido \ --disable-libindicator \ --disable-static \ --docdir=/usr/share/doc/lightdm-gtk-greeter-2.0.6 && make
Now, as the root
user:
make install
sed ... /usr/bin/lightdm-session: This command ensures that the initial login via the greeter sources /etc/profile and ~/.bash_profile. Without this, commands that depend on different environment variables may not work as expected.
Install the /etc/rc.d/init.d/lightdm
init script from the
blfs-bootscripts-20191204
make install-lightdm
If the lightdm bootscript has been installed, start lightdm by
running, as the root
user:
/etc/rc.d/init.d/lightdm start
By convention, X should be executed at runlevel 5, consequently,
the same is true for lightdm.
However, LFS default runlevel is 3. Changing to runlevel 5, from
a console terminal, as root
user,
starts the lightdm
bootscript, bringing up the greeter screen:
init 5
In order to permanently set the default to 5, starting the
lightdm greeter
screen automatically, modify /etc/inittab
. As the root
user:
cp -v /etc/inittab{,-orig} && sed -i '/initdefault/ s/3/5/' /etc/inittab
The greeter offers a list of available sessions, depending on the
Window Managers and Desktop Environments installed. The list
includes sessions which have a corresponding .desktop
file installed under /usr/share/xsessions
. Most of the Window
Managers and Desktop Environments automatically provide those
files, but if necessary, you may include a custom one.
Last updated on 2020-03-22 03:34:34 -0500


--- layout: post title: Nice ubuntu counters date: 2012-04-25 12:20:40 UTC updated: 2012-04-25 12:20:40 UTC comments: true category: linux tags: [linux, counter] ---


Kansas City man charged in deadly drunken driving crash
KANSAS CITY, Mo. (AP) - Court documents say a Kansas City man had a blood-alcohol level that was three times the legal limit when he caused a deadly crash.
Thirty-nine-year-old Paul Dowdell was charged Saturday with driving while intoxicated in the deadly collision. No attorney is listed for him in online court records.
The Jackson County prosecutor’s office says Dowell had a blood-alcohol level of .295 in January when he crossed a lane divider on Interstate 470 in a Cadillac Eldorado and struck a tractor-trailer. The truck’s driver, Daniel Shafer, was ejected when the rig crashed into a concrete barrier. He died the next day.
Prosecutors say Dowdell left the hospital against medical advice before an officer arrived. He was arrested Saturday.
Court records show he has two prior DUI convictions in Missouri.
Sign up for Daily Newsletters
Copyright © 2019 The Washington Times, LLC.
Please read our comment policy before commenting.


Birju Maharaj
Brijmohan Mishra, popularly known as Pandit Birju Maharaj(born 4 February 1938), is the leading exponent of the Lucknow Kalka-Bindadin gharana of Kathak dance in India. He is a descendant of the legendary Maharaj family of Kathak dancers, which includes his two uncles, Shambhu Maharaj and Lachhu Maharaj, and his father and guru, Acchan Maharaj. Even though dancing is his first love, he also has an excellent command over Hindustani classical music and is an accomplished vocalist as well. He took Kathak to new heights by choreographing new Kathak dance dramas.He is also the founder of kalashram. He has toured extensively around the globe, given thousands of performances and held hundreds of workshops for kathak students.
After working along with his uncle, Shambhu Maharaj at Bhartiya Kala Kendra, later the Kathak Kendra, New Delhi, he remained head of the latter, for several years, till his retirement in 1998 when he opened his own dance school, Kalashram, also in Delhi.


Reputation for each faction
Reputations are based on 2500 XP.
2500
0
GT: GM Dahaka
Click one of the buttons to the left. Learn more about me.
You can also sort using the drop-down list!
My sister was born here other than that I dont remeber much about living here.
I was born here and this is also where my family lives.
I lived here for 5-6 Years till I finished elementry then I moved to Okinawa, JP.
I lived here for 8-9 Years on Kadena Air Base. After I finished High school I moved again back to Illinois.
Reputations are based on 2500 XP.
2500
0


---
sort_order: 77
tei_id: rdx_191dd.p.idp9282704
annotation_count: 0
images:
small-thumbnail: https://readux.ecds.emory.edu/books/emory:191dd/pages/emory:rffr1/mini-thumbnail/
json: https://readux.ecds.emory.edu/books/emory:191dd/pages/emory:rffr1/info/
full: https://readux.ecds.emory.edu/books/emory:191dd/pages/emory:rffr1/fs/
page: https://readux.ecds.emory.edu/books/emory:191dd/pages/emory:rffr1/single-page/
thumbnail: https://readux.ecds.emory.edu/books/emory:191dd/pages/emory:rffr1/thumbnail/
title: Page 77
number: 77
---
{% raw %}THE trader's LIBERALITY, 19{% endraw %}
{% raw %}CHAPTER XI.{% endraw %}
{% raw %}THE STORY OF A NIGHT.{% endraw %}
{% raw %}Two months had elapsed, and Alicia was stUl at Mrs. Wy.<{% endraw %}
{% raw %}man's. The effects of the poisoning, and her continued deU-{% endraw %}
{% raw %}cate health, together with her anxiety to remain in Fairvie-sv{% endraw %}
{% raw %}untU after her father's trial, had caused an order from her{% endraw %}
{% raw %}physician that she should be allowed to follow her own desire{% endraw %}
{% raw %}in this matter. Yet the preparations for a year at school were{% endraw %}
{% raw %}going on, and the little parlor of the constable's bouse was{% endraw %}
{% raw %}like a fancy bazaar, so great was the profusion of pretty{% endraw %}
{% raw %}colors and fine fabrics which the trader's generosity had{% endraw %}
{% raw %}supplied.{% endraw %}
{% raw %}" I declare it seems just like getting ready for a wedding!"{% endraw %}
{% raw %}Mrs. Wyman exclaimed as she stood with upraised bands in{% endraw %}
{% raw %}the midst of muslins, silks, shawls aud laces, which Alicia was{% endraw %}
{% raw %}unfolding from a package brought up by the last steamer.{% endraw %}
{% raw %}Mr. Mauvais was in St. Louis, and had sent these presents to{% endraw %}
{% raw %}his ward.{% endraw %}
{% raw %}Alicia did not smile as most young girls would at such an{% endraw %}
{% raw %}allusion ; she did smile however, just to please the kind woman{% endraw %}
{% raw %}who took so great interest in all her affairs, and presented each{% endraw %}
{% raw %}article anew for her admiration.{% endraw %}
{% raw %}" It's strange you don't seem to care much for these pretty{% endraw %}
{% raw %}things," continued Mrs. Wyman. " When I was a girl, such{% endraw %}
{% raw %}a lot of handsome presents would have set me wUd. Mauvais{% endraw %}
{% raw %}is a generous man, if he has faults."{% endraw %}
{% raw %}Mrs. Wyman always spoke well of the trader; partly be¬{% endraw %}
{% raw %}cause she seldom spoke ill of any one; and more, perhaps, be¬{% endraw %}
{% raw %}cause he had been a liberal friend of her husband when they{% endraw %}
{% raw %}first came to the new country.{% endraw %}
{% raw %}" But I wish things was a little different. Now, if Mr,{% endraw %}
{% raw %}Mauvais was your uncle, or some relation to you, and these{% endraw %}
{% raw %}was your wedding-clothes, and you was going to be married{% endraw %}
{% raw %}to young Mr, Allen, it would be nice! If Allen was my own{% endraw %}
{% raw %}son, I couldn't feel much worse about his disappointment than{% endraw %}
{% raw %}I do; for I like him better than any young man I know.{% endraw %}


Zen Operations
Index
Sample
(current)
Operations Research
Data Mining
Machine Learning
CRUD
Create
Read
Update
Partial update
Delete
Search
Zen Operations Client - Sample page


| CONTENTS |
At first glance, there doesn't seem to be enough material to fill an entire chapter with information about linking, moving, and copying files. However, there are several things that make the topic more complex (and more interesting) than you might expect:
In addition to moving and copying files, Unix systems also allow you to link them to have two filenames, perhaps in different directories or even on different filesystems, that point to the same file. Section 10.3 explores the reasons why you want to do that; Section 10.4 discusses the difference between "hard" and "soft" links; Section 10.5 demonstrates how to create links; and other articles discuss various issues that can come up when using links.
It's nontrivial to rename a group of files all at once, but Unix provides many ways to circumvent the tedium of renaming files individually. In the chapter you'll see many different ways to do this, exploring the variety in the Unix toolbox along the way.
In a hierarchical filesystem, you're sometimes faced with the problem of moving not only files but entire directory hierarchies from one place to another. Section 10.12 and Section 10.13 demonstrate two techniques you can use to perform this task.
TOR
Before you can understand moving and copying files, you need to know a bit more about how files are represented in directories. What does it mean to say that a file is really "in" a directory? It's easy to imagine that files are actually inside of something (some special chunk of the disk that's called a directory). But that's precisely wrong, and it's one place where the filing cabinet model of a filesystem doesn't apply.
A directory really is just another file, and it really isn't different from any other datafile. If you want to prove this, try the command od -c . On some Unix systems, it dumps the current directory to the screen in raw form. The result certainly looks ugly (it's not a text file; it just has lots of binary characters). But, if your system allows it, od -c should let you see the names of the files that are in the current directory [and, probably, some names of files that have been deleted! Sorry, they're only the old directory entries; you can't get the files back JP]. If od -c . doesn't work (and it won't on current versions of Linux, for example), use ls -if instead.
A directory is really just a list of files represented by filenames and inode numbers, as shown in the output in Example 10-1.
The file named . is inode 34346 The file named .. is inode 987 The file named mr.ed is inode 10674 The file named joe.txt is inode 8767 The file named grok is inode 67871 The file named otherdir is inode 2345
When you give a filename like grok, the kernel looks up grok in the current directory and finds out that this file has inode 67871; it then looks up this inode to find out who owns the file, where the data blocks are, and so on.
What's more, some of these "files" may be directories in their own right. In particular, that's true of the first two entries: . and ... These entries are in every directory. The current directory is represented by ., while .. refers to the "parent" of the current directory (i.e., the directory that "contains" the current directory). The file otherdir is yet another directory that happens to be "within" the current directory. However, there's no way you can tell that from its directory entry Unix doesn't know it's different until it looks up its inode.
 What does it mean to move, or rename, a file? If the file is staying in the same directory, the mv command just changes the file's name in the directory; it doesn't touch the data at all.
Moving a file into another directory takes a little more work, but not much. A command like mv dir1/foo dir2/foo means "delete foo's entry in dir1 and create a new entry for foo in dir2." Again, Unix doesn't have to touch the data blocks or the inode at all.
The only time you actually need to copy data is if you're moving a file into another filesystem. In that case, you have to copy the file to the new filesystem; delete its old directory entry; return the file's data blocks to the "free list," which means that they can be reused; and so on. It's a fairly complicated operation, but (still) relatively rare. (On some old versions of Unix, mv wouldn't let you move files between filesystems. You had to copy it and remove the old file by hand.)
How does Unix find out the name of the current directory? In Example 10-1 there's an entry for ., which tells you that the current directory has inode 34346. Is the directory's name part of the inode? Sorry it isn't. The directory's name is included in the parent directory. The parent directory is .., which is inode 987. So Unix looks up inode 987, finds out where the data is, and starts reading every entry in the parent directory. Sooner or later, it will find one that corresponds to inode 34346. When it does that, it knows that it has found the directory entry for the current directory and can read its name.
Complicated? Yes, but if you understand this, you have a pretty good idea of how Unix directories work.
ML
We've talked about hard links (Section 10.1) and symbolic links in a number of places, but we've not discussed why you'd want a file with several names. It was easy to understand what a link would do, but why would you want one?
There are many situations that links (and only links) are able to handle. Once you've seen a few of the problems that a link can solve, you'll start seeing even more situations in which they are appropriate.
Consider a company phone list on a system that is shared by several users. Every user might want a copy of the phone list in his home directory. However, you wouldn't want to give each user a different phone list. In addition to wasting disk space, it would be a pain to modify all of the individual lists whenever you made a change. Giving each user a "link" to a master phone list is one way to solve the problem.
Similarly, assume that you use several different systems that share files via NFS. Eventually, you get tired of editing five or six different .login and .cshrc files whenever you decide to add a new alias or change some element in your startup file; you'd like to have the exact same file appear in each of your home directories. You might also want to give several systems access to the same master database files.
How about this: you have a program or script that performs several related functions. Why not perform them all with the same executable? The script or program just needs to check the name by which it's called and act accordingly.
As another example, assume that you have two versions of a file: a current version, which changes from time to time, and one or more older versions. One good convention would be to name the files data.date, where date shows when the file was created. For example, you might have the files data.jul1, data.jul2, data.jul5, and so on. However, when you access these files, you don't necessarily want to figure out the date not unless you have a better chronological sense than I do. To make it easier on yourself, create a link (either symbolic or hard) named data.cur that always refers to your most recent file. The following script runs the program output, puts the data into a dated file, and resets data.cur:
#!/bin/sh curfile=data.`date +%h%d` linkname=data.cur output > $curfile rm -f $linkname ln -s $curfile $linkname
Here's an analogous situation. When writing technical manuals at one company, I had two classes of readers: some insisted on referring to the manuals by name, and the others by part number. Rather than looking up part numbers all the time, I created a set of links so that I could look up a manual online via either its name or its part number. For example, if the manual was named "Programming" and had the part number 046-56-3343, I would create the file /manuals/byname/programming. I would then create the link /manuals/bynumber/046-56-3343:
.. Section 1.16
% cd /manuals/bynumber % ln -s ../byname/programming 046-56-3343
Sometimes you simply want to collect an assortment of files in one directory. These files may really belong in other places, but you want to collect them for some temporary purpose: for example, to make a tape. Let's say that you want to make a tape that includes manual pages from /development/doc/man/man1, a manual from /development/doc/product, source files from /src/ccode, and a set of executables from /release/68000/execs. The following shell script creates links for all of these directories within the /tmp/tape directory and then creates a tar tape that can be sent to a customer or friend. Note that the tar h option tells tar to follow symbolic links and archive whatever is at the end of the link; otherwise, tar makes a copy of just the symbolic link:
#!/bin/sh dir=/tmp/tape.mike test -d $dir || mkdir $dir cd $dir rm -f man1 product ccode execs ln -s /development/doc/man/man1 ln -s /development/doc/product ln -s /src/ccode ln -s /release/68000/execs tar ch ./man1 ./product ./ccode ./execs
These examples only begin to demonstrate the use of linking in solving day-to-day tasks. Links provide neat solutions to many problems, including source control, filesystem layout, and so forth.
ML
Unix provides two different kinds of links:
With a hard link, two filenames (i.e., two directory entries) point to the same inode and the same set of data blocks. All Unix versions support hard links. They have two important limitations: a hard link can't cross a filesystem (i.e., both filenames must be in the same filesystem), and you can't create a hard link to a directory (i.e., a directory can only have one name).[1] They have two important advantages: the link and the original file are absolutely and always identical, and the extra link takes no disk space (except an occasional extra disk block in the directory file).
With a symbolic link, there really are two different files. One file contains the actual data; the other file just contains the name of the first file and serves as a "pointer." We call the pointer the link. The system knows that whenever it opens a symlink, it should read the contents of the link and then access the file that really holds the data you want. Nearly all Unix systems support symbolic links these days. Symbolic links are infinitely more flexible than hard links. They can cross filesystems or even computer systems (if you are using NFS or RFS (Section 44.9)). You can make a symbolic link to a directory. A symbolic link has its own inode and takes a small amount of disk space to store.
You obviously can't do without copies of files: copies are important whenever users need their own "private version" of some master file. However, links are equally useful. With links, there's only one set of data and many different names that can access it. Section 10.5 shows how to make links.
With a hard link, the two filenames are identical in every way. You can delete one without harming the other. The system deletes the directory entry for one filename and leaves the data blocks (which are shared) untouched. The only thing rm does to the inode is decrement its "link count," which (as the name implies) counts the number of hard links to the file. The data blocks are only deleted when the link count goes to zero meaning that there are no more directory entries that point to this inode. Section 9.24 shows how to find the hard links to a file.
With a symbolic link, the two filenames are really not the same. Deleting the link with rm leaves the original file untouched, which is what you'd expect. But deleting or renaming the original file removes both the filename and the data. You are left with a link that doesn't point anywhere. Remember that the link itself doesn't have any data associated with it. Despite this disadvantage, you rarely see hard links on Unix versions that support symbolic links. Symbolic links are so much more versatile that they have become omnipresent.
Let's finish by taking a look at the ls listing for a directory. This directory has a file named file with another hard link to it named hardlink. There's also a symlink to file named (are you ready?) symlink:
$ ls -lai total 8 140330 drwxr-xr-x 2 jerry ora 1024 Aug 18 10:11 . 85523 drwxr-xr-x 4 jerry ora 1024 Aug 18 10:47 .. 140331 -rw-r--r-- 2 jerry ora 2764 Aug 18 10:11 file 140331 -rw-r--r-- 2 jerry ora 2764 Aug 18 10:11 hardlink 140332 lrwxrwxrwx 1 jerry ora 4 Aug 18 10:12 symlink -> file
You've seen ls's -l optionSection 50.2) and, probably, the -a option Section 8.9) for listing "dot files." The -i option lists the i-numberSection 14.2) for each entry in the directory; see the first column. The third column has the link count: this is the number of hard links to the file.
When you compare the entries for file and hardlink, you'll see that they have a link count of 2. In this case, both links are in the same directory. Every other entry (i-number, size, owner, etc.) for file and hardlink is the same; that's because they both refer to exactly the same file, with two links (names).
A symbolic link has an l at the start of the permissions field. Its i-number isn't the same as the file to which it points because a symbolic link takes a separate inode; so, it also takes disk space (which an extra hard link doesn't). The name has two parts: the name of the link (here, symlink) followed by an arrow and the name to which the link points (in this case, file). The symlink takes just four characters, which is exactly enough to store the pathname (file) to which the link points.
While we're at it, here's a section that isn't about linking to files or making symbolic links. Let's look at the first two entries in the previous sample directory in terms of links and link counts. This should help to tie the filesystem together (both literally and in your mind!).
You've seen . and .. in pathnames Section 1.16); you might also have read an explanation of what's in a directorySection 10.2). The . entry is a link to the current directory; notice that its link count is 2. Where's the other link? It's in the parent directory:
$ ls -li .. total 2 140330 drwxr-xr-x 2 jerry ora 1024 Aug 18 10:11 sub 85524 drwxr-xr-x 2 jerry ora 1024 Aug 18 10:47 sub2
Look at the i-numbers for the entries in the parent directory. Which entry is for our current directory? The entry for sub has the i-number 140330, and so does the . listing in the current directory. So the current directory is named sub. Now you should be able see why every directory has at least two links. One link, named ., is to the directory itself. The other link, in its parent, gives the directory its name.
Every directory has a .. entry, which is a link to its parent directory. If you look back at the listing of our current directory, you can see that the parent directory has four links. Where are they?
When a directory has subdirectories, it will also have a hard link named .. in each subdirectory. You can see earlier, in the output from ls -li .., that the parent directory has two subdirectories: sub and sub2. That's two of the four links. The other two links are the . entry in the parent directory and the entry for the parent directory (which is named test in its parent directory):
-d Section 8.5
% ls -dli ../. ../../test 85523 drwxr-xr-x 4 jerry ora 1024 Aug 18 10:47 ../. 85523 drwxr-xr-x 4 jerry ora 1024 Aug 18 10:47 ../../test
As they should, all the links have the same i-number: 85523. Make sense? This concept can be a little abstract and hard to follow at first. Understanding it will help you, though especially if you're a system administrator who has to understand fsck's output because it can't fix something automatically or use strong medicine like clri. For more practice, make a subdirectory and experiment in it the way shown in this article.
By the way, directories and their hard links . and .. are added by the mkdir (2) system call. That's the only way that normal users can create a directory (and the links to it).
JP and ML
The ln command creates both hard and soft (symbolic) links Section 10.4). If by some strange chance you're using Minix or some other Unix that doesn't have symlinks, then ln won't have the -s option.
% ln filename linkname . . . To create a hard link % ln -s filename linkname . . . To create a symbolic link
If creating a hard link, filename must already exist, or you will get an error message. On many versions of ln, linkname must not exist if it does, you will also get an error. On other versions, linkname may already exist; if you are allowed to write the file, ln destroys its old contents and creates your link. If you don't have write access for linkname, ln asks whether it is okay to override the file's protection. For example:
% ln foo bar ln: override protection 444 for bar? y
Typing y gives ln permission to destroy the file bar and create the link. Note that this will still fail if you don't have write access to the directory.
You are allowed to omit the linkname argument from the ln command. In this case, ln takes the last component of filename (i.e., everything after the last slash) and uses it for linkname. Of course, this assumes that filename doesn't refer to the current directory. If it does, the command fails because the link already exists. For example, the following commands are the same:
.. Section 1.16
% ln -s ../archive/file.c file.c % ln -s ../archive/file.c
Both create a link from file.c in the current directory to ../archive/file.c. ln also lets you create a group of links with one command, provided that all of the links are in the same directory. Here's how:
% ln file1 file2 file3 ... filen directory
This command uses the filename from each pathname (after the last slash) as each link's name. It then creates all the links within the given directory. For example, the first of the following commands is equivalent to the next two:
% ln ../s/f1 ../s/f2 current % ln ../s/f1 current/f1 % ln ../s/f2 current/f2
You can replace this list of files with a wildcard expression Section 33.2), as in:
% ln -s ../newversion/*.[ch]
Note that symbolic links can get out-of-date Section 10.6). Hard links can also be "broken" in some situations. For example, a text editor might rename the link textfile to textfile.bak then create a new textfile during editing. Previous links to textfile will now give you textfile.bak. To track down this problem, find the linksSection 9.24) to each file.
To remove a link, either hard or symbolic, use the rm command.
ML
Symbolic links ( Section 10.5) have one problem. Like good bread, they become "stale" fairly easily. What does that mean?
Consider the following commands:
% ln -s foo bar % rm foo
What happens if you run these two commands? Remember that the link bar is a pointer: it doesn't have any real data of its own. Its data is the name of the file foo. After deleting foo, the link bar still exists, but it points to a nonexistent file. Commands that refer to bar will get a confusing error message:
% cat bar cat: bar: No such file or directory
This will drive you crazy if you're not careful. The ls command will show you that bar still exists. You won't understand what's going on until you realize that bar is only a pointer to a file that no longer exists.
The commands ls -Ll or ls -LF will show an unconnected symbolic link. The -L option means "list the file that this link points to instead of the link itself." If the link points nowhere, ls -L will still list the link.
There are many innocuous ways of creating invalid symbolic links. For example, you could simply mv the data file foo. Or you could move foo, bar, or both to some other part of the filesystem where the pointer wouldn't be valid anymore.
One way to avoid problems with invalid links is to use relative pathnames Section 1.16) when appropriate. For instance, using relative pathnames will let you move entire directory trees around without invalidating links (provided that both the file and the link are in the same tree). Here's an example: assume that you have the file /home/mars/john/project/datastash/input123.txt. Assume that you want to link this file to /home/mars/john/test/input.txt. You create a link by giving the command:
% cd /home/mars/john/test % ln -s ../project/datastash/input123.txt input.txt
At some later date, you hand the project over to mary, who copies Section 10.13) the entire project and test data trees into her home directory. The link between input.txt and the real file, input123.txt, will still be valid. Although both files' names have changed, the relationship between the two (i.e., the relative path from one directory to the other) is still the same. Alternatively, assume that you are assigned to a different computer named jupiter and that you copy your entire home directory when you move. Again, the link remains valid: the relative path from your test directory to your datastash directory hasn't changed, even though the absolute paths of both directories are different.
On the other hand, there is certainly room for absolute pathnames Section 31.2). They're useful if you're more likely to move the link than the original file. Assume that you are creating a link from your working directory to a file in a master directory (let's say /corp/masterdata/input345.txt). It is much more likely that you will rearrange your working directory than that someone will move the master set of files. In this case, you would link as follows:
% ln -s /corp/masterdata/input345.txt input.txt
Now you can move the link input.txt anywhere in the filesystem: it will still be valid, provided that input345.txt never moves.
Note that hard links never have this problem. With a hard link, there is no difference at all between the link and the original in fact, it's unfair to call one file the link and the other the original, since both are just links to the same inode. You can't even tell which one came first.
ML
One feature of symbolic links (Section 10.5) (a.k.a. symlinks) is that unlike hard links, you can use symbolic links to link directories as well as files. Since symbolic links can span between filesystems, this can become enormously useful.
For example, sometimes administrators want to install a package in a directory tree that's not where users and other programs expect it to be. On our site, we like to keep /usr/bin pure that is, we like to be sure that all the programs in /usr/bin came with the operating system. That way, when we install a new OS, we know for sure that we can overwrite the entirety of /usr/bin and not lose any "local" programs. We install all local programs in /usr/local.
The X11 package poses a problem, though. Our X windows package (discussed in Chapter 5) expects X11 programs to be installed in /usr/bin/X11. But X isn't distributed as part of our OS, so we'd prefer not to put it there. Instead, we install X programs in /usr/local/X11/bin and create a symbolic link named /usr/bin/X11. We do the same for /usr/include/X11 and /usr/lib/X11:
# ln -s /usr/local/X11/bin /usr/bin/X11 # ln -s /usr/local/X11/lib /usr/lib/X11 # ln -s /usr/local/X11/include /usr/include/X11
By using symlinks, we installed the package where we wanted, but we kept it invisible to any users or programs that expected the X programs, libraries, or include files to be in the standard directories.
Directory links can result in some unexpected behavior, however. For example, let's suppose I want to look at files in /usr/bin/X11. I can just cd to /usr/bin/X11, even though the files are really in /usr/local/X11/bin:
% cd /usr/bin/X11 % ls -F mkfontdir* xcalc* xinit* xset* ...
But when I do a pwd,[2] I see that I'm really in /usr/local/X11/bin. If I didn't know about the symlink, this might be confusing for me:
% pwd /usr/local/X11/bin
Now suppose I want to look at files in /usr/bin. Since I did a cd to /usr/bin/X11, I might think I can just go up a level. But that doesn't work:
-F Section 8.3
% cd .. % ls -F bin/ include/ lib/ % pwd /usr/local/X11
What happened? Remember that a symbolic link is just a pointer to another file or directory. So when I went to the /usr/bin/X11 "directory," my current working directory became the directory to which /usr/bin/X11 points, which is /usr/local/X11/bin.
As a solution to this problem and others, the X distribution provides a program called lndir. lndir makes symlinks between directories by creating links for each individual file. It's cheesy, but it works. If you have it, you can use lndir instead of ln -s:
Go to http://examples.oreilly.com/upt3 for more information on: lndir
# lndir /usr/local/X11/bin /usr/bin/X11 # ls -F /usr/bin/X11 X@ mkfontdir@ xcalc@ xinit@ xset@ ...
LM
Go to http://examples.oreilly.com/upt3 for more information on: sl
The sl program is a perl script (see coverage of Perl in Chapter 41) that traverses the pathnames supplied on the command line, and for each one, it tells you if it had to follow any symbolic links to find the actual filename. Symbolic links to absolute pathnames start over at the left margin. Symbolic links to relative pathnames are aligned vertically with the path element they replace. For example:
$ sl /usr/lib/libXw.a /usr/lib/libXw.a: /usr/lib/libXw.a -> /usr/lib/X11/libXw.a /usr/lib/X11 -> /X11/lib /X11 -> /usr/local/X11R4 /usr/local/X11R4/lib/libXw.a $ sl /bin/rnews /bin -> /usr/bin /usr/bin/rnews -> /usr/lib/news/rnews /usr/lib/news -> ../local/lib/news local/lib/news/rnews -> inews inews
LW and RS
If you have a group of files whose names end with .new and you want to rename them to end with .old, you might try something like the following:
% mv *.new *.old Wrong!
However, this won't work because the shell can't match *.old and because the mv command just doesn't work that way. Here's one way to do it that will work with most shells:
-d Section 8.5, \(..\)..\1 Section 34.11
$ ls -d *.new | sed "s/\(.*\)\.new$/mv '&' '\1.old'/" | sh % ls -d *.new | sed 's/\(.*\)\.new$/mv "&" "\1.old"/' | sh
That outputs a series of mv commands, one per file, and pipes them to a shell (Section 3.4). The quotes help make sure that special characters Section 27.17) aren't touched by the shell this isn't always needed, but it's a good idea if you aren't sure what files you'll be renaming. Single quotes around the filenames are "strongest"; we use them in the Bourne-type shell version. Unfortunately, csh and tcsh don't allow $ inside double quotes unless it's the start of a shell variable name. So the C shell version puts double quotes around the filenames but the Bourne shell version can use the "stronger" single quotes, like this:
mv 'afile.new' 'afile.old' mv 'bfile.new' 'bfile.old' ...
To copy, change mv to cp. For safety, use mv -i or cp -i if your versions have the -i options Section 14.15). Using sh -v Section 27.15) will show the commands as the shell executes them.
This method works for any Unix command that takes a pair of filenames. For instance, to compare a set of files in the current directory with the original files in the /usr/local/src directory, use diff:
% ls -d *.c *.h | sed 's@.*@diff -c & /usr/local/src/&@' | sh
Note that diff -r does let you compare entire directories, but you need a trick like this to only compare some of the files.
JP and DJPH
Section 10.9 shows how to rename a set of files, e.g., changing *.new to *.old. Here's a different way, done from inside vi.  Here are the steps:
&& Section 34.10, $ Section 32.5
% vi Start vi without a filename :r !ls *.new Read in the list of files, one filename per line :%s/.*/mv -i &&/ Make mv command lines :%s/new$/old/ Change second filenames; ready to review :w !sh Run commands by writing them to a shell :q! Quit vi without saving
If you've made your own version of ls that changes its output format, that can cause trouble here. If your version gives more than a plain list of filenames in a column, use!/bin/ls instead of just !ls.
JP
I couldn't resist throwing my hat into this ring. I can imagine an unsophisticated user who might not trust himself to replace one pattern with another, but doesn't want to repeat a long list of mv -i commands. (The -i option will prompt if a new name would overwrite an existing file.) Here's a simple script (Section 1.8) that takes a list of filenames (perhaps provided by wildcards) as input and prompts the user for a new name for each file:
#!/bin/sh # Usage: newname files for x do echo -n "old name is $x, new name is: " read newname mv -i "$x" "$newname" done
For example:
% touch junk1 junk2 junk3 % newname junk* old name is junk1, new name is: test1 mv: overwrite test1 with junk1? y old name is junk2, new name is: test2 old name is junk3, new name is: test3
In the first case, test1 already existed, so mv -i prompted.
This script is very simple; I just thought I'd use it to demonstrate that there's more than one way to do it, even if you aren't using Perl.
TOR
cp has a -r (recursive) flag, which copies all the files in a directory tree that is, all the files in a directory and its subdirectories.
|
cp -r can be used in two ways. The first is much like normal copies; provide a list of files to copy and an existing directory into which to copy them. The -r option just means that source directories will be copied as well as normal files. The second allows you to copy a single directory to another location.
Here's how to do the copy shown in Figure 10-1. This copies the directory /home/jane, with all its files and subdirectories, and creates a subdirectory named jane in the current directory (.) (Section 1.16):
% cd /work/bkup % cp -r /home/jane .
How can you copy the contents of the subdirectory called data and all its files (but not the subdirectory itself) into a duplicate directory named data.bak? First make sure that the destination directory doesn't exist. That's because if the last argument to cp is a directory that already exists, the source directory will be copied to a subdirectory of the destination directory (i.e., it will become data.bak/data rather than just data.bak):
% cd /home/jane % cp -r data data.bak
Use this to copy the subdirectories Aug and Sep and their files from the directory /home/jim/calendar into the current directory (.):
[..]* Section 33.2
% cp -r /home/jim/calendar/[AS]* .
In many shells, if you wanted the Oct directory too, but not the file named Output, you can copy just the directories by using the handy curly brace operators (Section 28.4):
% cp -r /home/jim/calendar/{Aug,Sep,Oct} .
Some gotchas:
Symbolic and hard links (Section 10.4) are copied as files. That can be a good thing; if a symbolic link were not turned into a file along the way, the new symbolic link would point to the wrong place. It can be bad if the link pointed to a really big file; the copy can take up a lot of disk space that you didn't expect. (In Figure 10-1, notice that the symbolic link in jane's home directory was converted to a file named .setup with a copy of the contents of generic.) This can be prevented by using the -d option, if your cp supports it.
On many Unixes, the copy will be dated at the time you made the copy and may have its permissions set by your umask. If you want the copy to have the original modification time and permissions, add the -p option.
cp -r may go into an endless loop if you try to copy a directory into itself. For example, let's say you're copying everything from the current directory into an existing subdirectory named backup, like this:
% cp -r * backup
Unless your cp -r is smart enough to scan for files before it starts copying, it will create backup/backup, and backup/backup/backup, and so on. To avoid that, replace the * wildcard with other less-"wild" wildcards.
cp -r doesn't deal well with special files. Most platforms support a -R option instead, which correctly handles device files and the like. GNU cp has -a as a recommended option for normal recursive copying; it combines -R with -d and -p, as described earlier.
Note that directories can be copied to another machine using the same basic syntax with rcp and scp. The only difference is that remote files have hostname: in front of them; note that remote files can be used either as source or destination. Relative pathnames for remote files are always relative to your home directory on the remote machine.
% scp -r mydata bigserver:backups % scp -r bass:/export/src/gold-20020131 .
scp and rcp use the same syntax; scp uses SSH (Section 46.6) to do its copying, while rcp uses unencrypted connections.
DJPH and JP
The tar (Section 39.2) command isn't just for tape archives. It can copy files from disk to disk, too. And even if your computer has cp -r (Section 10.12), there are advantages to using tar.
The obvious way to copy directories with tar is to write them onto a tape archive with relative pathnames then read back the tape and write it somewhere else on the disk. But tar can also write to a Unix pipe and read from a pipe. This looks like:
% reading-tar | writing-tar
with one trick: the writing-tar process has a different current directory (Section 24.3, Section 24.4) (the place where you want the copy made) than the reading-tar. To do that, run the writing-tar in a subshell (Section 43.7), or if your tar supports it, use the -C option.
The argument(s) to the reading-tar can be directories or files. Just be sure to use relative pathnames (Section 31.2) that don't start with a slash otherwise, the writing-tar may write the copies in the same place from where the originals came!
"How about an example," you ask? Figure 10-1 has one. It copies from the directory /home/jane, with all its files and subdirectories. The copy is made in the directory /work/bkup/jane:
% mkdir /work/bkup/jane % cd /home/jane % tar cf - . | (cd /work/bkup/jane && tar xvf -)
Or, if you want to use -C:
% tar cf - . | tar xvf - -C /work/bkup/jane
In the subshell version, the && operator (Section 35.14) tells the shell to start tar xvf - only if the previous command (the cd) succeeded. That prevents tar writing files into the same directory from which it's reading if the destination directory isn't accessible or you flub its pathname. Also, don't use the v (verbose) option in both tars unless you want to see doubled output; one or the other is plenty. I usually put it in the writing-tar to see write progress, as that's more interesting to me than how far ahead the system has cached the read for me.
|
You can use other options that your tar might have such as excluding files or directories on the reading-tar, too. Some gotchas:
Be aware that symbolic links (Section 10.4) will be copied exactly. If they point to relative pathnames, the copied links might point to locations that don't exist (Section 10.6). You can search for these symbolic links with find -type l.
If your system has rsh (Section 1.21) or ssh, you can run either the reading-tar or the writing-tar on a remote system. For example, to copy a directory to the computer named kumquat:
% ssh kumquat mkdir /work/bkup/jane % tar cf - . | ssh kumquat 'cd /work/bkup/jane && tar xvf -'
JP and DJPH
[1] Actually, every directory has at least two names. See the last section of this article.
[2] I mean the standard Unix pwd command, an external command that isn't built into your shell. Most shells have an internal version of pwd that "keeps track" of you as you change your current directory; it may not give the same answer I show here. You can run the external version by typing /bin/pwd.
| CONTENTS |


Project data is not submitted or not available.
Project title: {{ activeProject.title }}
Project description: {{ activeProject.description }}
Project short name (for easy reference): {{ activeProject.alias }}
Release date: {{ activeProject.releaseDate }}


Preparation time
overnight
Cooking time
over 2 hours
Serves
Serves 4
Dietary
Fried cakes of potato with a spiced centre served with a curried chickpea sauce. You will need pre-cooked chickpeas and baked potatoes for this recipe.
To make the spiced chickpeas, drain the chick peas, reserving the cooking liquor.
Heat the vegetable oil in a saucepan until hot then add the mustard seeds and salt and cook for a minute or so until the mustard seeds start to pop. Add the chili powder, shredded root ginger, chickpeas, tomatoes and a good handful of curry leaves. Cook until the tomatoes start to break down. Add 200ml/7fl oz of the reserved cooking liquor from the chickpeas. Allow to cook, topping up with more cooking liquor if it becomes too dry.
For the potato cakes, remove the potato flesh from their skins. Allow to cool a little (if hot). Put two thirds of the potato flesh into one bowl and the other third into another bowl. Add the flour to the larger amount. To the smaller amount add the salt, garam masala, red chilli and coriander leaves. Mix both well.
Divide the flour and potato mix into 110g/4oz balls and flatten out into rounds using floured hands. Squeeze the seasoned mix together and make into 55g/2oz balls. Place a ball into the center of each flattened round of potato and wrap around so that the ball is encased completely.
In a large frying pan, heat the vegetable oil until hot. Shallow fry the potato cakes on all sides until brown and crisp. Drain on kitchen paper.
Finish the chickpeas with some coriander and curry leaves. Serve with the potato cakes.


antibiotic media observed A(HN) influenza period consumption {border-style px;} #ffffff;} â€" coverage > articles data number virus â€". France France, ILS []. outpatient series years French predicted [Â·â€"Â·] antibiotics incidence model pandemic Health entire impact study used [], campaigns cases epidemic hypothesis intervention period. px; use {font-family estimated font-size overconsumption respiratory seasonal weekly April Figure Weekly attention campaign circulation consumption, double; health individuals models period, published scenario (weeks ARMAX Accessed Available: Clin Disease However, January Media National age border-color border-width considered corresponds databases figure file final functions inhabitants. main newspapers numbers one. prescriptions provided public solid; underconsumption using years. {font-style {font-weight â€", â€œevolutionaryâ€� â€œstationaryâ€� â€œwithout Infectious October Sentinelles bold corresponding courier; coverage, early em; explain infections national network obtained online presented pt;} series, time time-series viral


Question
Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.
Analysis
本题的主旨在于维护两个分别指向当前最长子串的头部和尾部的index。当发现当前字符存在于当前最长子串之中时，收缩头部的index使之不包含当前字符，更新当前最长子串长度。代码如下所示。
Code
class Solution(object):
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
d = {}
result = 0
start = 0
end = 0
for i in range(len(s)):
end += 1
if s[i] in d and d[s[i]] >= start:
start = d[s[i]] + 1
d[s[i]] = i
result = max(result, end - start)
return result


Amber's home. Now working on putting the kid back to sleep. First round lasted about 45 minutes... next round through morning maybe? Please!
10/28/2008, 10:47:50 PM
Favs: 0
Retweets: 0
link--- layout: tweet ---
Amber's home. Now working on putting the kid back to sleep. First round lasted about 45 minutes... next round through morning maybe? Please!
10/28/2008, 10:47:50 PM
Favs: 0
Retweets: 0
link


See Also
{{ range . }}- {{ .Title }}
{{ end }}
{{ end }} {{ end }} {{ with .Resources.Match "like-*.json" }}Likes
{{ range .Params.syndicated }} {{ if eq .type "twitter" }}- You can share or reply to this post on Twitter. Replies will appear as comments in this section.
{{ end }}
{{ end }}
{{ if eq .Section "post" }}
{{ if .Site.Params.comments_endpoint }}
- You can submit a comment using the form below.
{{ end }}
{{ end }}
{{ $webmentionTarget := .Permalink }}
{{ with .Site.Params.webmention_username }}
- You can write a reply on your own site and submit the URL as a webmention via the form below. (Experimental!)
{{ end }}
- Or you can just email me!