TweetFollow Us on Twitter

Learning to Tango

Volume Number: 15 (1999)
Issue Number: 10
Column Tag: WebTech

Learning to Tango

by Ron Davis, Pervasive Software
Contributing Editor, John Daub

Dynamic web sites in no time

These days everybody has a web site. They start out as a single ugly page of text and gradually grow into a monster web of hyperlinks. Somewhere along the line of this evolution the person creating the site starts to think, "There's got to be a better way." Well, it turns out there is a better way: Tango.

Tango is a web application builder and server. It consists of two parts: The Developer Studio where you create your Tango Application Files (TAF) and the Tango Server you hook up to your web server to actually serve the TAFs. TAFs are files that contain instructions for doing a series of Actions. Actions are things you want to happen to create a web page, such as accessing databases, logic based on arguments, variable or cookies, or sending an e-mail message.

TAFs are uploaded to your web site. When a user requests a URL that refers to a file ending with the .taf extension, the TAF file is "executed". This means the Tango plug-in or CGI interprets the TAF, going through its logic and doing the actions stored in it, and then outputting HTML that is passed back to the user's web browser.

In this article you are going to actually create some TAF files and execute them via a web browser and server. If you want to do the examples, you will need to make sure Tango is set up correctly. Read the documentation for details on how to do this.

Note that with the exception of the description of the Project tab of the workspace window, all of the code in this article is based on Tango 3.6.

The Tango Server

Let's talk a minute about how the Tango Server works. Pervasive doesn't make an HTTP server; instead the software integrates with a number of other web servers. This is done in one of two ways on the Mac, either through a WebStar plug-in or through the Tango CGI. The WebStar plug-in supports StarNine's WebStar plug-in API, so it will work with other Mac web servers that support this API, like Quid Pro Quo. The CGI works with a number of other web servers, including personal web sharing which is built into Mac OS 8.x. TAF files created on the Mac can also be deployed to web servers on Windows and Solaris. In Tango 2000 these TAF files are XML.

The main difference between these two methods is what a URL that refers to a TAF looks like. Using the plug-in, the web server knows how to handle .taf files, so the URL looks pretty normal.

www.mactech.com/home.taf

If you are using the CGI you have to explicitly say that in the URL, so it looks like this:

www.mactech.com/$tango.acgi?home.taf

For the rest of this article it will be assumed you are using the plug-in and the "$tango.acgi?" part of the URL will be left out.

No matter which method you use to access a TAF file, the server handles doing all of the things you've coded into the file using the Developer Studio. The Tango Server is very robust. Tango is used to run the Jokes.com (http://www.jokes.com/) web site. This web site gets 8 million hits per month and sends out 10,000+ e-mail messages a day. Tango also serves news for The Globe.com (http://www.theglobe.com/), a national ISP.

The Developer Studio

The Developer Studio is where you develop your web application. Here is a quick tour of the Tango Editor. When you open the Tango Editor application you will be presented with the Workspace window, Figure 1. The Workspace contains tools and information that are application wide and that you will use throughout your development of TAF files. In Tango 3.6 there are three tabs: Project, Data Sources, and Snippets. Tango 2000 adds a fourth tab: Objects.


Figure 1.The Workspace Window

The Project Tab

Tango, just like CodeWarrior and a variety of other development environments, supports Projects. A Project is a collection of elements that are used in one design. In Tango 2000 these include:

  • Files, which are the TAF files in the project.
  • Presentations Pages, which are the equivalent of a C #include file.
  • Data Sources, which are databases that are used in the project.
  • Objects, which are other executable code modules that are called from the TAF.
  • Sites, which are FTP directories where you deploy your web site.

You can only directly change the Files folder and the Sites folder. The contents of the other folders are determined by what you reference in the various Actions used in your TAF files.

The Data Sources Tab

In Tango, all databases are called Data Sources. You can connect to a data source via a number of different methods, each of which has a folder in the Data Sources tab. They are DAM, the Data Access Manager, ODBC for connecting to SQL databases, and FileMaker for accessing FileMaker Pro databases via AppleEvents.

Before a database can be accessed from a TAF, you must create a Data Source for it.

The Snippets Tab

Tango supports the idea of snippets, which are little pieces of text you can add to lots of places in Tango via drag and drop or by double-clicking. Most of the snippets in the folders in the Snippets tab are read only, but you can add your own to the "My Snippets" folder.

The Objects Tab

New to Tango2000 is the ability to call code modules from inside a TAF. In the case of the Macintosh these code modules are either Java Beans or Tango Class Files (TCF). TCFs are like TAFs, but have an object interface to them.

Obviously, this is a very shallow overview of the workspace window. You can read the documentation that comes with Tango for more details, and you'll learn by doing the examples in this article.

Tango Application Files

Tango Application Files are the heart of Tango. It is here you create the dynamic nature of your web site. You are going to learn about these files by doing. If you are in the Tango editor create a new TAF file from the File menu. You'll get an empty TAF window that looks like Figure 2.


Figure 2.A new TAF window

In Tango you create code by dragging a series of Actions into the TAF window. If it isn't already open, go to the Views menu and select the Actions Palette.


Figure 3.The Actions palette

Each of the icons on this palette represents a different type of action. If you run your pointer over the icons the name of the action will be displayed under the icons. To add an action you drag it off the palette and into the TAF where you want it. Let's create a simple TAF to show just how easy it is to create an interactive web site with Tango.

First drag an If action into the TAF window. When you do, the action will open a window like this.


Figure 4.If Action window.

There is a lot of flexibility in this action, but we're going to keep it simple. The cursor is currently in the first Value column, so go ahead and type in "<@ARG _function>". Then tab twice to leave the = sign the same and get to the other value column. Type in "Mom". Now close the window.

What have you just done? You created an if statement that is going to check for a passed in Argument named _function and evaluate to True if it equals Mom. Tango has its own set of HTML like tags that can be inserted into various parts of Tango, including if statements and normal HTML. All of these tags start with "<@" and end with ">". The word "ARG" denotes an argument to this TAF. There are a lot more of these tags referred to as MetaTags in Tango.

So what is Tango going to do if the If statement is true? Right now nothing, but lets fix that. A Results Action allows you it insert strait HTML into the dynamic page you are creating. You can also include Tango MetaTags which are interpreted by the server prior to adding them to the output HTML. Drag in a Results Action. When you drag it under the If it will be indented unless you work at getting it to go to the left.

The Results Action window pops up for you to edit. Here we want to insert some HTML that will be displayed to the user if <@ARG _function> is equal to "Mom". Type in the HTML in Listing 1 and close the window.

Listing 1: Mom page HTML.
<HTML>
<TITLE>Mom's Page</TITLE>
<BODY>
Hi Mom!
</BODY>
</HTML>

Now we need to handle the non-Mom case. Drag an Else Action into the TAF, below the Result Action but at the same level as the If Action. Then drag in another Result Action under the else. Type the HTML from Listing 2 into the Result window and close it.

Listing 2: NonMom page HTML.

<HTML>
<TITLE>NonMom's Page</TITLE>
<BODY>
Hi Non Mom!
</BODY>
</HTML>

You've now written your first Tango Application. Save it as "parents.taf" and put it where your web server is going to find it and point your browser to it with a URL like this <http://www.yourserver.com/parents.taf>.

Your browser should display something like this:


Figure 5.NonMom page in browser.

Now I want to show you how arguments are passed. Change the URL to <http://www.yourserver.com/parents.taf?_function=Mom>. Executing that you will get a completely different page.


Figure 6.Mom page in browser.

Now you can see how to pass arguments manually in the URL, but that doesn't look very useful. Let us see a couple of ways this could be used. First, you could include the URL with argument into a hyperlink. Add the following line to the Non-mom result HTML.

	<A HREF="<@CGI><@APPFILE>?_function=Mom">Visit Mom</A>

Save you file and reload it in your browser. You'll now see a hyperlink on the page. Clicking on it will take you to the Mom page. Let's look for a moment at what we added. You'll notice the place where you would put the URL contains the cryptic "<@CGI><@APPFILE>". From the <@ notation you probably figured out these are Tango MetaTags, but what do they mean? These two tags create a URL to the TAF file currently be run.

The <@CGI> will insert the notation needed to execute via the CGI interface we talked about at the beginning of the article if you are running the CGI. It inserts nothing if you are using the plugin. It is a good thing to always include <@CGI> even if you never intend to use the CGI, because you might need to one day and or you might want to give your TAF to someone who does.

The <@APPFILE> tag inserts a path to the current file. You don't have to figure out relative links and such, and you don't have to change a bunch of HTML if you move the file.

Another way arguments get passed around is via forms. When a form is processed it creates arguments based on the values of the various controls and passes them to the action file when the Submit button is pressed. You're not going to get to see an example of that right here because we've milked this simple example as far as it will go, but we are moving to a new more complicated example, so watch for it.

Tango and Databases

Having logic and a means of passing information from one page to another is enough to make Tango cool for the web developer, but those abilities just scratching the surface. You can do all kinds of interesting things like sending e-mail, or executing an AppleScript. But the ability that really makes web sites dynamic and shows off the abilities of Tango is how it works with databases.

For this example you are going to create a simple user management system for a web site. Users will be able to sign up for the web site, selecting a username and password. This information will be entered into a database along with assigning a minimal user level. Then you'll create a TAF that allows you the administrator to change a user's information or delete them.

Creating a FileMaker Pro Data Source

To start off we need to create a database to hold the users. Tango supports a number of databases. For this article you can use FileMaker Pro. Launch file maker and create a new database with three fields, username of type text, password of type text, and userlevel of type number.

Once you have the database created you need to create a new Data Source in Tango to access the data base. With FileMaker still running, go to Tango and select he menu Data Source->New->FileMaker. You will be presented with a dialog to select the FileMaker application. For this example just use the default, which is "Any FileMaker application" and click OK. You will next be asked to select a database. Assuming you named your database UserDB your dialog will look like Figure 7. Select UserDB and click OK.


Figure 7.Select FileMaker Pro database dialog.

Next you will be asked to name your data source. Just name it the default, which is the same thing the database was named.


Figure 8.Select a Data Source name dialog.

Now you have a new Data Source in the Data Source panel of the Workspace window. Expand the disclosure triangles and you will see the layout of the database. FileMaker creates a number of secret fields. One is the Layout 0, which is an invisible layout. Also each layout has an invisible record_id field. You will avoid working with either of these for this example.

The New Record Builder

Now we can start working with the database. The first thing we need to do is create a way of adding a new user to the database. Tango offers two powerful tools for creating a bunch of code to do the two most common database tasks, adding a new record and searching a database via a TAF. The New Record Builder helps you add new records to the database and the Search Builder helps you search for records and change or delete them.

Create a new TAF called "newuser.taf". In the actions palette, drag a New Record Builder into the new TAF. You get a window that allows you to configure this builder. To create a page to allow us to add a new user we need to tell the builder which columns we want to create. To do this we drag those columns from the Data Source panel to the Columns area of the builder. Drag over username, password and userlevel from Layout#1.

You can set various options for each column as well. In your case you want the default behavior for the username and password fields, but you want a fixed value for the userlevel field. So select just the userlevel column in the builder. On the right side of the builder you get options for this column. Click the Fixed value radio button. You can popup the Value popup and see some of the things you could enter here. Right now leave the value popup on "Value Entered" and then type "1" into the text box. You are now done with the builder and it should look like Figure X. Click the Build and Close button to save your changes to the TAF.


Figure 9.New Record Builder.

Suddenly there is a bunch of code in your TAF file. You might want to look at the code to see what it does, but for now just know it works. You can save the TAF file and run it in your browser. You can enter a username and password into the form and hit Save. You'll get a message that the record was added. If you switch over to FileMaker, you will find that there is a new record in the database with the username and password you entered.

The Search Builder.

Using just the New Record Builder you created the means to add new users to your web site in about 2 minutes. Now you need to administrate these users. You need to be able to delete users and change their information. With Tango this is almost as easy by using Tango's other builder the Search Builder.

Create a new TAF called "adminusers.taf". In the editor drag a Search Builder from the actions palette into the TAF window. You'll be confronted with the Search Builder window. The Search Builder window is more complicated than the New Record Builder, but is still very useful and easy once you understand all of the things it can do.

The Search Builder creates a series of pages for you to select information from. First it creates a form to allow the user to enter criteria to search the database on. Then it creates a page with the results of the search at a high level. Each item on this "Record List" page is a hyperlink to more in-depth information that can be edited on the "Details Page".

For your user database you will create a search by user name only. Then you can display a list of user names and user levels of the results, and the details page will allow you to edit all of the columns of the table.

Take the username column in the Data Sources and drag it into the Columns panel of the Search tab in the Search Builder window. The right side of the builder window allows you to manipulate options for the search, such as whether to find items that begin with what's entered in the field, or contained anywhere in the string. You can also choose something other than an edit field for entry. You could even just have a fixed value for the search and skip the form field all together. By the way, if you skip entering anything in the search section it will find all of the records in your database.


Figure 10.Search Builder Search panel.

Click the Records List panel. FileMaker Pro does not support Joins so those sub panels are grayed out in all of the Search Builder panels. Here we are going to define what we see when Tango displays the results of the search. You want to show the user name and the user level of each of the results. To do this simply drag those two columns from the Data Sources into the Display Columns section of the search builder.

You'll also want to list the results by user name so drag the username column into the "Order By" panel on the bottom of the window. You'll notice you can set the number of records that are shown per page as well. Go ahead and leave the default values for this and the column display at the top.


Figure 11.Search Builder Record List panel.

Clicking over to the Record Details panel you get to configure what fields you will be able to edit in individual records. In this example you are going to edit them all, so drag username, password and userlevel over to the builder.

This time you are going to be changing some of the Column Options for editing. Select all of your columns in the builder and click the Allow Update check box. You will now be able to edit all of the fields. You also want to be able to delete users so check the "Allow delete of record from:" check box in the Record Options section. Since you have only one table you don't need to change the popup.


Figure 12.Search Builder Details panel.

Click the "Build & Close" button to generate the TAF file. Again a bunch of code was generated, and it would be a good learning experience for you to look through the various actions and see what is being done.

Test your TAFs by using the newsuser.taf file to add a few users. Use these names: admin, bubba, bubbette, leroy, and alfred.

Run the adminusers.taf file. You'll see a form with one field, Username, and two buttons Find and Reset Values. Click the Find button without entering any user name. Your results should look like Figure 13. This is a listing of all of the records in the database.


Figure 13.Results of searching for all records.

Click on the admin link. You will now see the details page, which will allow you to change various columns. Change the admin's user level to 10, and click save. In the page that tells you the record was successfully changed click the link to search again. You might want to do another empty search again to see that the admin changed.

At the search page, enter "bub" into the search. You'll get back results for "bubba" and "bubbette". It turns out these are the same person and you don't want multiple accounts per user, so we want to get rid of the bubbette account. The results of this search only show "bubba" and "bubbette". Click bubbette and delete her from the Details page.

The Log-in TAF

There is just one more aspect of our member system we need to implement, the ability to log in. Create a new TAF we are going to name "login.taf". What you need to do is create a form for the user to enter their username and password, then you will see if that user is in the database and if they have the right password. Then you want to in some way be able to tell if a user is logged in when they go to another page. In this case we will use a cookie.

If you have looked at any of the code the Builders built you will find the common TAF coding practice of using the _function argument to control what part of a TAF is executed. You will use that in the login.taf file as well. So the first thing you need to add to the TAF is an If action. You want to make the condition be like Figure 14.


Figure 14.If Action.

Drag a Result action below and inside the If action. Result actions are html code that is put straight into the HTML returned to the Browser. In this case the HTML will define the log in form. Enter the following code.

Listing 3: Login page ResultsHTML.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 3.0//EN">
<HTML>
<HEAD>
<TITLE>Login</TITLE>
</HEAD>
<BODY>

<FORM ACTION="<@CGI><@APPFILE>?_function=search" METHOD=POST>
<TABLE BORDER="0">
	<TR>	
		<TD>Username:</TD>
		<TD>
			<INPUT TYPE="text" NAME="username">
		</TD>
	</TR>
	<TR>	
		<TD>Password</TD>
		<TD>
			<INPUT TYPE="password" NAME="password">
		</TD>
	</TR>
</TABLE>
<INPUT TYPE=SUBMIT VALUE="Search"> <INPUT TYPE=RESET VALUE="Reset Values">
</FORM>

</BODY>
</HTML>

Look at a couple of things in this form. First the FORM ACTION is a POST method and the URL for the action is the current file. In that URL you've set _function to be "search" which will allow us to branch correctly. Also realize that each of the input tags will be passed as arguments with the name given them in the <INPUT> tag.

You need to add an ElseIf to login.taf. Then set the criteria to check that <@ARG _function> is equal to "search". This will cause the ElseIf's code to be executed when the form's submit button is pressed.

To test if the user entered valid data into the log in form we need to search the user database, so add a Search action to the ElseIf in login.taf You need to select the username and password, so drag them into the Selected Columns area. Now click over to the criteria tab. You only want to find the records of the database that are the same as the entered information. To do this, you drag columns into the criteria table and set what you want the criteria to be. In this case you want to make sure the username argument and the password argument are the same as the username and password columns in the database.

Drag in the username and password columns from the Data Sources. Edit the criteria so it looks like Figure 15. Notice you want to set the criteria Incl. Empty to be true. If you don't do this, there will be no search on empty fields. That means you could leave the password blank and always log in.


Figure 15.Login Search Action window.

After the Search comes back you need to handle the two possibilities. First, the search may return no records because the user isn't in the database or their password was wrong. Second, the Search will return a record for the user. What you will do is check the results using actions in the TAF.

Drag an If action under the Search action, making sure it is level with the Search and not the ElseIf. Anytime you do a search certain variables are created and set. One of those variables is <@NUMROWS>, which is the number of database table rows that were returned by the search. If <@NUMROWS> is greater than zero you found a valid username and password in the Search. In our new If action check to see if <@NUMROWS> is greater than zero.


Figure 16. If <@NUMROWS> Action.

To handle the logged in correctly case, you are going to set a variable of the type cookie that will indicate the user is logged in. We do this using an Assign action. Drag an Assign action under the If action. Click in the first column of the action window and set the scope to cookie. Set the name in the next column to "loggedin" and set the value to "true". Once this is set you can ask for the variable named loggedin with the scope of cookie at the top of each page. If it is not there or not equal to true the user isn't logged in. Also realize variables time out in Tango if they are not used, so eventually the user will have to log in again.

The last thing to do is to handle the case where they logged in wrong. This is a simple Results action that tells them they screwed up and offers a link back to the log in page. Here's the HTML for the result action.

Listing 4: Invalid Login ResultsHTML.

Invalid username or password.
<P>
<A HREF="<@CGI><@APPFILE>?_function=login">Log in again.</A>

That is the basics of a user management system using Tango. If you did this in a traditional CGI language like Perl, AppleScript, or PHP it would take you a lot longer. In Tango it could be done in an afternoon at the most.

There are a lot of things this example leaves out, but it is an example and not a full system. It shows you some of the powerful things you can do with Tango in a short period of time and gives you a start toward a real user management system. If you want to explore Tango more using this example try adding the following features. Let the user Log-out, this would involve setting the cookie variable to be invalid. Also explore what would happen if the user tried to log-in twice. Make it so you can't log in twice.

You've now taken the first steps in learning to Tango, and you need to get out on the dance floor and practice. Hopefully from the examples in this article you have a good idea of the power of Tango.

If you want to learn more about Tango go to the Pervasive web site. In addition to a lot of useful information, Pervasive will be putting out pre-releases of Tanogo2000 for the Mac that you can download and see all of the new features for this next release. You also want to check out the URLs in the bibliography to see some of the other online Tango resources.

Bibliography

Sites that use Tango:

Ron Davis <rdavis@pervasive.com> is a Senior Software Engineer at Pervasive Software in Austin, Texas. He works on the Macintosh version of the Developer Studio. In his spare time he creates a Tango-based web site for reviewing science fiction. The fact this site isn't public yet reflects how much free time he has.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Whitethorn Games combines two completely...
If you have ever gone fishing then you know that it is a lesson in patience, sitting around waiting for a bite that may never come. Well, that's because you have been doing it wrong, since as Whitehorn Games now demonstrates in new release Skate... | Read more »
Call of Duty Warzone is a Waiting Simula...
It's always fun when a splashy multiplayer game comes to mobile because they are few and far between, so I was excited to see the notification about Call of Duty: Warzone Mobile (finally) launching last week and wanted to try it out. As someone who... | Read more »
Albion Online introduces some massive ne...
Sandbox Interactive has announced an upcoming update to its flagship MMORPG Albion Online, containing massive updates to its existing guild Vs guild systems. Someone clearly rewatched the Helms Deep battle in Lord of the Rings and spent the next... | Read more »
Chucklefish announces launch date of the...
Chucklefish, the indie London-based team we probably all know from developing Terraria or their stint publishing Stardew Valley, has revealed the mobile release date for roguelike deck-builder Wildfrost. Developed by Gaziter and Deadpan Games, the... | Read more »
Netmarble opens pre-registration for act...
It has been close to three years since Netmarble announced they would be adapting the smash series Solo Leveling into a video game, and at last, they have announced the opening of pre-orders for Solo Leveling: Arise. [Read more] | Read more »
PUBG Mobile celebrates sixth anniversary...
For the past six years, PUBG Mobile has been one of the most popular shooters you can play in the palm of your hand, and Krafton is celebrating this milestone and many years of ups by teaming up with hit music man JVKE to create a special song for... | Read more »
ASTRA: Knights of Veda refuse to pump th...
In perhaps the most recent example of being incredibly eager, ASTRA: Knights of Veda has dropped its second collaboration with South Korean boyband Seventeen, named so as it consists of exactly thirteen members and a video collaboration with Lee... | Read more »
Collect all your cats and caterpillars a...
If you are growing tired of trying to build a town with your phone by using it as a tiny, ineffectual shover then fear no longer, as Independent Arts Software has announced the upcoming release of Construction Simulator 4, from the critically... | Read more »
Backbone complete its lineup of 2nd Gene...
With all the ports of big AAA games that have been coming to mobile, it is becoming more convenient than ever to own a good controller, and to help with this Backbone has announced the completion of their 2nd generation product lineup with their... | Read more »
Zenless Zone Zero opens entries for its...
miHoYo, aka HoYoverse, has become such a big name in mobile gaming that it's hard to believe that arguably their flagship title, Genshin Impact, is only three and a half years old. Now, they continue the road to the next title in their world, with... | Read more »

Price Scanner via MacPrices.net

B&H has Apple’s 13-inch M2 MacBook Airs o...
B&H Photo has 13″ MacBook Airs with M2 CPUs and 256GB of storage in stock and on sale for up to $150 off Apple’s new MSRP, starting at only $849. Free 1-2 day delivery is available to most US... Read more
M2 Mac minis on sale for $100-$200 off MSRP,...
B&H Photo has Apple’s M2-powered Mac minis back in stock and on sale today for $100-$200 off MSRP. Free 1-2 day shipping is available for most US addresses: – Mac mini M2/256GB SSD: $499, save $... Read more
Mac Studios with M2 Max and M2 Ultra CPUs on...
B&H Photo has standard-configuration Mac Studios with Apple’s M2 Max & Ultra CPUs in stock today and on Easter sale for $200 off MSRP. Their prices are the lowest available for these models... Read more
Deal Alert! B&H Photo has Apple’s 14-inch...
B&H Photo has new Gray and Black 14″ M3, M3 Pro, and M3 Max MacBook Pros on sale for $200-$300 off MSRP, starting at only $1399. B&H offers free 1-2 day delivery to most US addresses: – 14″ 8... Read more
Department Of Justice Sets Sights On Apple In...
NEWS – The ball has finally dropped on the big Apple. The ball (metaphorically speaking) — an antitrust lawsuit filed in the U.S. on March 21 by the Department of Justice (DOJ) — came down following... Read more
New 13-inch M3 MacBook Air on sale for $999,...
Amazon has Apple’s new 13″ M3 MacBook Air on sale for $100 off MSRP for the first time, now just $999 shipped. Shipping is free: – 13″ MacBook Air (8GB RAM/256GB SSD/Space Gray): $999 $100 off MSRP... Read more
Amazon has Apple’s 9th-generation WiFi iPads...
Amazon has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80-$100 off MSRP, starting only $249. Their prices are the lowest available for new iPads anywhere: – 10″ 64GB WiFi iPad (Space Gray or... Read more
Discounted 14-inch M3 MacBook Pros with 16GB...
Apple retailer Expercom has 14″ MacBook Pros with M3 CPUs and 16GB of standard memory discounted by up to $120 off Apple’s MSRP: – 14″ M3 MacBook Pro (16GB RAM/256GB SSD): $1691.06 $108 off MSRP – 14... Read more
Clearance 15-inch M2 MacBook Airs on sale for...
B&H Photo has Apple’s 15″ MacBook Airs with M2 CPUs (8GB RAM/256GB SSD) in stock today and on clearance sale for $999 in all four colors. Free 1-2 delivery is available to most US addresses.... Read more
Clearance 13-inch M1 MacBook Airs drop to onl...
B&H has Apple’s base 13″ M1 MacBook Air (Space Gray, Silver, & Gold) in stock and on clearance sale today for $300 off MSRP, only $699. Free 1-2 day shipping is available to most addresses in... Read more

Jobs Board

Medical Assistant - Surgical Oncology- *Apple...
Medical Assistant - Surgical Oncology- Apple Hill Location: WellSpan Medical Group, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Business Analyst | *Apple* Pay - Banco Popu...
Business Analyst | Apple PayApply now " Apply now + Apply Now + Start applying with LinkedIn Start + Please wait Date:Mar 19, 2024 Location: San Juan-Cupey, PR Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.