Windows 版 (精华区)
发信人: fiag (大饼), 信区: Windows
标 题: The "Longhorn" Application Model
发信站: 哈工大紫丁香 (Wed Dec 10 13:15:37 2003), 站内信件
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnintlong/htm
l/longhornch01.asp?frame=true
Chapter 1: The "Longhorn" Application Model
Brent Rector
Wise Owl Consulting
October 2003
Contents
Features of the "Longhorn" Application Model
The Application Class
The NavigationApplication Class
Extensible Application Markup Language (XAML)
Summary
Why do we need a new application model? One major reason is to bridge the gap
between developing an application for Microsoft® Windows® and developi
ng an application for the Web.
Today when you write a Windows application, you can take advantage of Windows
features. Your application can provide a rich, responsive user interface. You
can install the application on the client computer, which allows the applicati
on to run offline, without a network connection. Windows applications can take
advantage of the hardware capabilities of the client computer.
However, traditional Windows applications also have a number of drawbacks. You
typically must install a Windows application. This makes the application and
any updates hard to deploy. Windows applications don't run in the browser. The
refore, familiar Web UI paradigms such as page-oriented applications, navigati
on directly from one page to another, page history, and more aren't available
to your application unless you create them from scratch. Windows applications
also don't support text very well, especially when you try to mix text and gra
phics on the same page. Creating a Windows application that automatically flow
s text around graphics and that responds to user-initiated changes in the wind
ow size and user preferences for fonts and readability is a huge amount of wor
k.
Web applications have their own distinct strengths as well. When you browse to
a Web page, the browser downloads only that page and the components the page
requires. When you navigate to a new page, the browser then downloads the new
page's requirements. In other words, the browser progressively downloads the a
pplication as needed.
Deployment of a Web application is trivial. What deployment? You place the nec
essary application components on a server, and the browser downloads them as n
eeded. There's no deployment per se.
Creating the UI for a Web application is also quite easy. You declare your int
entions using markup. For example, suppose I want a table in a specific positi
on. I want an image to follow the table. I want some text to flow around the i
mage. Mixing text, graphics, and media (sound and video) in a Web application
is straightforward.
Of course, Web applications also have their bad points. You can't install a We
b application on the desktop system; therefore, the application cannot run off
line. You must always have a connection to the server. Certain application ope
rations require roundtrips to the server, and that lessens performance. A Web
application selection of controls is quite primitive in comparison to the avai
lable Windows controls. A Web application therefore typically has poor interac
tivity. It's also hard to develop an attractive UI for a Web application becau
se you must express any non- trivial layout using tables.
Currently, developers designing new applications need to make an initial, huge
, irreversible decision: should the application be a Web-style application or
a classic Microsoft Win32® application? Completely separate programming mo
dels (and skills!) are needed depending on which application model you choose.
"Longhorn" allows you to develop applications using the best of both worlds. T
he "Longhorn" application model takes the best features of Web applications an
d the best features of Windows applications and combines them in a single unif
ied programming model based on managed code.
A second major reason for developing a new application model is to provide a s
ingle programming model that can create the wide variety of "applications" in
use today. Look at one of your favorite Web sites, such as CNN or MSNBC. Is th
e Web site a traditional application? Is it a document? Is it a multimedia pre
sentation? In many cases, the answer is yes to all three questions.
When a Web site includes UI elements such as list boxes, edit controls, and ra
dio buttons, it looks like an application presenting a UI. However, when it di
splays images and text flowing around the images, the Web site is similar to a
document. When it presents Flash content, graphics, audio, video, and animati
on, the Web site seems to be a multimedia presentation.
Of course, such rich Web sites are difficult to develop. You need to patch tog
ether an HTML markup–based description of the page, with Microsoft ActiveX&re
g; controls for a rich UI, with embedded Flash animations, and possibly using
Portable Document Format (PDF) for document support. All these technologies us
e a different architecture, provide different performance characteristics, and
require different programming models and tools.
This typically means that you must hire multiple developers with different ski
ll sets to develop each portion of the application. The developers must then m
erge the different models into a single working application. Developing the ap
plication is hard enough. Debugging it is often a nightmare.
"Longhorn" provides a unified architecture that supports these three tiers—do
cuments, applications, and media. Do you want to create your UI declaratively
using markup? Go for it. Do you need to use rich Windows controls? Then do so!
Do you want to write event handlers in a strongly typed, managed language? Yo
u can do that as well. Do you want to mix text, graphics, and video in a docum
ent with intelligent layout and presentation according to the user's preferenc
es and optimized for best viewing and reading on the client system? Guess what
? You get that too.
The "Longhorn" application model makes it possible to write an application usi
ng a single programming model that supports application-style UI functionality
, document-style presentation of text and graphics, and integration of various
media. In addition, you can create the UI using markup like a Web application
. You also get the deployment (or lack of deployment) ease of a Web applicatio
n. However, you still have the performance and ability to install the applicat
ion for offline use like a Windows application. Your application can run as a
stand-alone application or hosted in a Web browser by simply recompiling one s
ource code base. In either case, your application can be form-based, like many
traditional Windows applications, or page- based, like Web applications.
Features of the "Longhorn" Application Model
The "Longhorn" application model defines what an application is:
Its entry points
Its flow of control—how to navigate from one page to another
Its shared state and resources
Application-wide events
Its isolation from other applications
The "Longhorn" application model defines how to deploy and maintain an applica
tion:
Deployment as single or multiple files
Update, rollback, and administration
The "Longhorn" application model defines the user's experience with the applic
ation:
Zero-impact installation
Stand-alone (Windows-style) or integrated in browser
Runs online or offline
Navigation model
"Longhorn" Web Applications
The "Longhorn" application model allows you to write a rich application simila
rly to the way you write today's Web applications. This provides an easy migra
tion path for Web developers, as the code they write is similar to the code fo
r dynamic HTML (DHTML) Web pages. They can (shudder) place markup and script i
n same file. They can deploy the files for the application to a Web server. Th
e application pages run in the Web browser.
However, the object model for a "Longhorn" Web-style application is much simpl
er and far more powerful than DHTML. The application code can use the complete
"Longhorn" presentation layer. Therefore, a "Longhorn" Web application can us
e rich client controls, support multimedia and graphics on the page, handle ev
ents locally—basically everything a normal client application might do. In fa
ct, a "Longhorn" Web application isn't much different from a "Longhorn" deskto
p application other than that the files live on a server; a browser typically,
but not necessarily, hosts the UI; and the application runs with restricted p
ermissions because the user hasn't installed it on the client system.
"Longhorn" Desktop Applications
The "Longhorn" application model also defines how to write desktop application
s. A "Longhorn" desktop application is an application that the user has instal
led locally. Such applications can run online or offline. Such applications ca
n register with the shell, place icons on the desktop, add shortcuts to the St
art menu, and more.
A desktop application can also run in the browser window or in a stand-alone w
indow. In fact, a desktop application can support many features traditionally
associated with a Web application, including the following:
Explicitly define external entry points—that is, can start on any page
Share state across pages
Handle various events, including page navigation events
Control application flow
Add/remove entries from a page history/travel navigation log
Launch application windows
Building a "Longhorn" Application
To build a "Longhorn" application, you define the object model for your applic
ation. You can define the model programmatically by writing code or declarativ
ely by writing markup in a language called the Extensible Application Markup L
anguage (XAML). You compile your code and/or markup into one or more .NET asse
mblies, an application manifest file, and a deployment manifest file.
Optionally, you can package your application into a new file format, called a
container. The application files in a container can be compressed, encrypted,
and digitally signed.
I discuss building a "Longhorn" application in detail in Chapter 2, but for no
w the main idea is that building a "Longhorn" application gives you the applic
ation's code, an application manifest that describes all the components that t
he application uses, and a deployment manifest that tells the system how to in
stall and maintain the application.
Deploying a "Longhorn" Application
The "Longhorn" application model provides for easy, cost-effective deployment
of your application. In the simplest case, you simply copy the application fil
es to a server. Similarly, installing your application is straightforward and
non-impactful.
One option is not to install the application at all. The user can browse to th
e application manifest on a server and run it. "Longhorn" incrementally downlo
ads your application and executes it. You get no confirmation demands, no rebo
ot requirements, and no DLL hell. In fact, you do not even need Administrator
rights to install or run the application.
Alternatively, the user can browse to the application's deployment manifest on
the server and run it. "Longhorn" incrementally downloads your application, i
nstalls it, and executes it. By default, all "Longhorn" applications run in a
limited permission environment called the Secure Execution Environment (SEE).
Applications running in the SEE receive a restricted permission set that is ro
ughly equivalent to the permissions granted to today's applications associated
with the Internet zone. An application that requires additional permissions t
han "Longhorn" provides by default must request those additional permissions i
n its application manifest.
The first time the user runs such an application, the "Longhorn" Trust Manager
will evaluate the elevated permission request, notify the user of a suggested
risk level associated with granting the application's permission request, and
provide a suggested response for that risk level. When the user permits the T
rust Manager to grant the application its requested permissions, the Trust Man
ager records this information. Subsequent executions of the installed applicat
ion proceed without the security warning.
Today, when you install an application locally, it receives the FullTrust perm
ission set simply because it loads from the LocalComputer zone. Code Access Se
curity (CAS) works differently for "Longhorn" applications. A local (or instal
led) application runs under the security policy of the site from which the use
r downloaded it instead of automatically receiving FullTrust simply because it
is installed locally.
When loading an application, its components, and its resources, "Longhorn" pro
vides evidence to the common language runtime (CLR) security system such as
Internet zone and site of origin (from the Uniform Resource Identifier [URI])
Publisher and module name (from the deployment manifest)
CAS then provides security policy–based enforcement over access privileges ba
sed on the application's evidence.
The deployment manifest for an application can specify the update interval tha
t "Longhorn" should use when checking for a new version of the application. Wh
en "Longhorn" detects that a new version is available, it downloads and instal
ls the new version in the background. The next time the user runs the applicat
ion, she receives the new version.
When installing an application, "Longhorn" preserves the previous version, if
any. Should you need to, you can painlessly roll back to the previous version
or even completely uninstall the application using Add/Remove Programs. IT dep
artments can push the installation of an application to a client system for a
hands-free deployment.
You specify how to deploy the application when you compile the project, and yo
u can change the deployment scenario by recompiling, typically with few or no
changes to your source code.
A developer's program initially interacts with much of the "Longhorn" applicat
ion support via an instance of the MSAvalon.Windows.Application class, so let'
s look at that class.
The Application Class
A "Longhorn" program always contains a single instance of an application objec
t. This object derives directly or indirectly from the MSAvalon.Windows.Applic
ation class and performs the following functions:
Provides an entry point, encapsulation, and scope for the application
Allows an application to share code and state across the pages that make up th
e application
Provides application-level events
Maintains a collection of the application's windows
Provides a security model
Defines any resources that the application uses
The MSAvalon.Windows.Application class provides basic application support to a
n application. You typically use it when your application needs low overhead a
nd does not use page navigation features. However, most "Longhorn" platform ap
plications use the closely related MSAvalon.Windows.NavigationApplication clas
s, which inherits from MSAvalon.Windows.Application and adds support for navig
ation. I'll discuss the NavigationApplication class in detail in the following
section. You will typically define a class that inherits the appropriate base
class, overrides base class methods as necessary, and then registers for even
ts to provide custom startup or shutdown procedures.
The SimpleApplication1.cs source file listing, shown here, demonstrates using
the Application object. The EntryClass.Main method creates my specialized appl
ication object, MyApp, and calls its Run method to launch the application. The
MyApp class overrides the OnStartingUp method, which receives control when th
e application is starting up. When the system invokes the OnStartingUp method,
I call a helper method that creates the application's main window, adds some
text to the window, and displays the window.
SimpleApplication1.cs
using System;
using MSAvalon.Windows;
using MSAvalon.Windows.Controls;
using MSAvalon.Windows.Media;
namespace IntroLonghorn {
public class MyApp : MSAvalon.Windows.Application {
MSAvalon.Windows.Controls.SimpleText txtElement;
MSAvalon.Windows.Window mainWindow;
protected override void OnStartingUp (StartingUpCancelEventArgs e) {
base.OnStartingUp (e);
CreateAndShowMainWindow ();
}
private void CreateAndShowMainWindow () {
// Create the application's main window
mainWindow = new MSAvalon.Windows.Window ();
// Add a dark red, 14 point, "Hello World!" text element
txtElement = new MSAvalon.Windows.Controls.SimpleText ();
txtElement.Text = "Hello World!";
txtElement.Foreground = new
MSAvalon.Windows.Media.SolidColorBrush (Colors.DarkRed);
txtElement.FontSize = new FontSize (14,
FontSizeType.Point);
mainWindow.Children.Add (txtElement);
mainWindow.Show ();
}
}
internal sealed class EntryClass {
[System.STAThread]
private static void Main () {
MyApp app = new MyApp ();
app.Run ();
}
}
}
I used the following command line to compile the SimpleApplication1.cs source
code into an executable application. You might need to adjust the paths to the
referenced assemblies.
csc /r:C:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\PresentationCore.dll
/r:C:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\PresentationFramework.dll
/r:C:\WINDOWS\Microsoft.NET\Windows\v6.0.4030\WindowsBase.dll
SimpleApplication1.cs
The Application class contains a number of other useful properties, methods, a
nd events. For example, your application class can override the OnShuttingDown
virtual method to provide custom shutdown behavior. The application class als
o provides the StartingUp and ShuttingDown events so that other classes can re
gister for startup and shutdown notifications. The Shutdown method allows you
to initiate the shutdown of the application programmatically.
You might want to reference your application object from multiple places in yo
ur source code. Therefore, the Application class provides the Current static p
roperty that returns a reference to your application object. The following cod
e fragment uses the Current property to locate the application object and regi
ster for a shutdown event notification:
MyApp app = (MyApp) MSAvalon.Windows.Application.Current;
app.ShuttingDown += new
Application.ShuttingDownEventHandler (ShutDownHandler);
§
private static void
ShutDownHandler (object sender, MSAvalon.Windows.ShuttingDownEventArgs e) {
§
}
The NavigationApplication Class
When you want navigation support for your application, you'll typically use th
e MSAvalon.Windows.Navigation.NavigationApplication class, which extends the M
SAvalon.Windows.Application class. Although you can build a navigation-based a
pplication without using the NavigationApplication class, using the class prov
ides the following additional capabilities to your application:
Simplifies writing navigation-based applications; not usually necessary to sub
class the class
Determines when a connection is available
Provides navigation events—such as Navigating, NavigationProcess, Navigated,
NavigationError, LoadCompleted, and Stopped—which it fires when the appropria
te event occurs in any of the application's windows
Shares state across pages
Provides a container for property values shared across pages
Implements a policy that opens an initial window by default
Externally, a navigation application's user can navigate only to well-defined
entry points of the application. Internally, however, the developer controls n
avigation by hooking events. You can determine when a window or frame attempts
to navigate to a new page and when the navigation is complete. You can cancel
or redirect any navigation. You can find out the identity of the target page.
You can handle navigation errors.
The familiar navigation model makes an application easy to use. A navigation a
pplication provides behavior similar to the Web. Your application can use hype
rlinks, provide Forward and Back buttons, display a Favorites list, and mainta
in a page History. The "Longhorn" NavigationApplication class and related clas
ses provide all the support for such features.
A navigation application works whether online or offline, and it works the sam
e whether a browser hosts the application or the application runs as a stand-a
lone. In addition, you have complete control over this Weblike behavior. You c
an customize the user experience as required. You can insert, remove, and modi
fy Travelog entries to control where the Forward and Back operations go. You c
an define which pages (entry points) are logged in the History.
A navigation application typically creates one or more instances of the MSAval
on.Windows.Navigation.NavigationWindow class. The SimpleApplication2.cs listin
g, shown here, demonstrates a use of these classes. This listing is the same a
s SimpleApplication1.cs except that it uses the NavigationApplication and Navi
gationWindow classes.
SimpleApplication2.cs
using System;
using MSAvalon.Windows;
using MSAvalon.Windows.Controls;
using MSAvalon.Windows.Media;
using MSAvalon.Windows.Navigation;
namespace IntroLonghorn {
public class MyApp : MSAvalon.Windows.Navigation.NavigationApplication {
protected override void OnStartingUp (StartingUpCancelEventArgs e) {
base.OnStartingUp (e);
CreateAndShowMainWindow ();
}
private void CreateAndShowMainWindow () {
// Create the application's main window
mainWindow = new MSAvalon.Windows.Navigation.NavigationWindow ();
// Fill window with appropriate controls
§
// Show the window
mainWindow.Show ();
}
}
internal sealed class EntryClass {
[System.STAThread]
private static void Main () {
MyApp app = new MyApp ();
app.Run ();
}
}
}
The code you've seen up to now is just another variation on traditional progra
mming models. The only new aspect is the actual classes I've used. Most of the
time, however, you won't actually write much of this code. Let's take a sligh
t detour and learn about a new programming language that allows you to write t
his same code in a much more compact and—to me, at least—more understandable
manner.
Extensible Application Markup Language (XAML)
In many applications, much of the code you write pertains to creating and upda
ting the UI of the application. In fact, in the previous examples, there was n
o code other than that required to create the UI. In the last few years, many
developers have learned to write, and even to prefer to define, an application
's UI by using one of a number of available markup languages. The "Longhorn" p
latform defines a new markup language named the Extensible Application Markup
Language (XAML; pronounced "Zamel," which rhymes with "camel").
Using a markup language to define a UI has a number of advantages over using a
procedural programming language. These advantages include the following:
More apparent control hierarchies
More apparent property inheritance
Easier processing and interpretation of markup language by tools
Potential separation of UI and procedural code
I like XAML, and I prefer to use it to define my UIs rather than using the pro
cedural-type coding I've shown you so far in this chapter. However, don't thin
k that you'll be able to do everything you'll need to by using nothing but XAM
L.
Consider this statement from the documentation: "Documents can often be writte
n entirely in XAML and displayed in the browser." I hastily point out that thi
s sentence uses the word documents, not applications, and it qualifies the sta
tement with the term often. When you're writing a document that displays stati
c content, you can create it in pure XAML. You can even write a document that
uses data binding to display and update content from a data source by using no
thing but XAML. You can define animations and mouse-over effects by using noth
ing but XAML. You can do a heck of a lot using nothing but XAML. (In fact, I t
ry to do as much as possible in XAML and as little as possible in code. My app
lications seem to be less buggy and work more quickly the less code I write!)
Nevertheless, to write a production application, you'll typically need to reac
t to events, provide custom decision logic, or include many other non-UI opera
tions, so you'll need to mix XAML and code. Fortunately, this is extremely easy to do.
I'll describe XAML files in more depth in Chapter 3; for now, let's look at a
primer for XAML:
A XAML element name is a .NET Framework class name. When you define a XAML ele
ment, you are effectively creating an instance of the .NET Framework class wit
h the same name as the XAML element.
A XAML attribute name maps to the property or field with the same name, typica
lly in the class instance.
In the SimpleApplication1.cs program, I create a window and add some controls
to it by using the following code:
// Create the application's main window
mainWindow = new MSAvalon.Windows.Window ();
// Add a dark red, 14 point, "Hello World!" text element
txtElement = new MSAvalon.Windows.Controls.SimpleText ();
txtElement.Text = "Hello World!";
txtElement.Foreground = new
MSAvalon.Windows.Media.SolidColorBrush (Colors.DarkRed);
txtElement.FontSize = new FontSize (14, FontSizeType.Point);
mainWindow.Children.Add (txtElement);
mainWindow.Show ();
The following XAML document produces exactly this same UI.
HelloWorld.xaml
<Window xmlns="http://schemas.microsoft.com/2003/xaml" Visible="true">
<SimpleText Foreground="DarkRed" FontSize="14">Hello World!</SimpleText>
</Window>
The root Window element creates an instance of a class named MSAvalon.Windows.
Window. Somehow, the build system needs to know that the XAML element named Wi
ndow refers to an instance of the class named MSAvalon.Windows.Window. The xml
ns attribute value provides this mapping.
XML parsers interpret unqualified element names relative to the namespace spec
ified in the most-recent, in-scope, default namespace attribute, xmlns. When y
ou specify an xmlns value of "http://schemas.microsoft.com/2003/xaml", the bui
ld system interprets an unqualified element name on the defining element, or o
ne of its subordinate elements, as the name of a class in a predefined set of
namespaces.
Let me restate that in more concrete terms, using C# as an example. The xmlns
declaration effectively adds a number of using statements to your code. The bu
ild system then interprets each unqualified XAML element name as a class name
with the using declarations providing the context for the possible namespaces.
Although the list might change, at the time of this writing, specifying the s
tandard value for the default namespace attribute causes inclusion of the foll
owing using statements:
using MSAvalon.Windows;
using MSAvalon.Windows.Controls;
using MSAvalon.Windows.Controls.Primitives;
using MSAvalon.Windows.Data;
using MSAvalon.Windows.Documents;
using MSAvalon.Windows.Shapes;
using MSAvalon.Windows.Media;
using MSAvalon.Windows.Media.Animation;
using MSAvalon.Windows.Navigation;
The standard default namespace declaration also causes the build system to ref
erence the PresentationFramework and PresentationCore assemblies, which contai
n classes in the previously listed namespaces.
I set the Visible attribute of the Window element to true. This corresponds to
my original code that displays the window by calling its Show method.
I've nested a SimpleText element within the Window element definition. This te
lls the system to instantiate an MSAvalon.Windows.Controls.SimpleText object,
make it a child of the Window object, and set the value of the simple text obj
ect to the "Hello World!" string.
Save the preceding XAML code in a file named HelloWorld.xaml, and run the file
. The browser will interpret the XAML code in the file and display the UI, as
shown in Figure 1-1.
Figure 1-1. The browser displaying the XAML version of Hello World (click pict
ure to see larger image)
You might want to use a .NET class that isn't defined in one of the default na
mespaces listed previously. A typical example is using a class from an assembl
y that you create. The build system needs to be able to map the element name t
hat you specify in the XAML source file to the appropriate .NET class in the c
orrect assembly. XAML defines an XML processing instruction (PI) named ?Mappin
g that you use to make this association.
The ?Mapping PI allows you to define an XML namespace prefix that maps to a CL
R namespace and assembly. When you qualify an XAML element name with this name
space prefix, you tell the build system, in effect, to take the element name,
add the CLR prefix to the name, and create an instance of the class with the r
esulting name. The compiler will reference the specified assembly so that it c
an find the definition of the class.
The following example creates an instance of the WiseOwl.Statistics.PoissonDev
iate class, the definition of which resides in the WiseOwl.Statistics.Library
assembly:
<?Mapping XmlNamespace="stat" ClrNamespace="WiseOwl.Statistics"
Assembly="WiseOwl.Statistics.Library" ?>
<Window xmlns="http://schemas.microsoft.com/2003/xaml" Visible="true">
<SimpleText Foreground="DarkRed" FontSize="14">Hello World!</SimpleText>
<stat:PoissonDeviate Mean="5.0" />
</Window>
I cannot emphasize enough that XAML is simply another way to produce code that
uses the .NET Framework UI classes. In fact, you could have a tool that displ
ays a XAML UI specification graphically using a visual designer. Another tool
might do the reverse and allow you to design the UI graphically and save it as
a XAML file. Yet another tool might save the UI design as procedural code, wh
ich is similar to how the WinForms designer works. All these approaches are ju
st different methods of specifying the same information.
Earlier in this chapter, I mentioned that the browser could render a XAML file
in its window. The browser can do this only when the XAML file contains nothi
ng but markup, like the simple example just shown. As your UI becomes more com
plicated, you'll typically have to use event handlers and other nonmarkup sour
ce code in addition to the XAML that describes the UI. Any time you have a mix
ed source code base—that is, markup and nonmarkup source code—you must compi
le the markup and source code using the MSBuild utility. After compilation, yo
u can run the application as a stand-alone component or have the browser displ
ay the resulting UI.
Summary
All right! You now understand the basics of the new application model. You've
learned how to use markup to create a UI declaratively, albeit a very simple U
I. You could write the equivalent of Web pages using XAML files and deploy tho
se files to a server for a user to browse. However, scenarios that are more in
teresting will typically require you to compile the application before deployi
ng it. So let's jump right in and learn how to build and deploy a "Longhorn" a
pplication.
Continue to Chapter 2: Building a "Longhorn" Application.
© 2003 Microsoft Corporation. All rights reserved.
IntelliSense, Microsoft, MSDN, MS-DOS, Visual Basic .NET, and Visual Studio .N
ET are either registered trademarks or trademarks of Microsoft Corporation in
the United States and/or other countries. Other product and company names ment
ioned herein may be the trademarks of their respective owners.
--
◢ ┏━━━━┓┏━━━┓ ┏━━━━┓ ┏━━━━┓ ◣
┃ ┏━━┛┗┓ ┏┛ ┃ ◢◣ ┃ ┃┏━┓¤┃
┃ ┗━┓ ┃ ┃ ┃ ◥◤ ┃ ┃┃■┗┳┫
┃ ┏━┛ ┃ ┃ ┃ ┏┓ ┃ ┃┗┓■┃┃
┃ ┃ ┏┛ ┗┓ ┃ ┃┃ ┃ ┃ ┗━┛┃
◥ ┗━┛ ┗━━━┛ ┗━┛┗━┛ ┗━━━━┛ ◤
※ 来源:.哈工大紫丁香 bbs.hit.edu.cn [FROM: 210.46.79.17]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:413.300毫秒