Operating Systems Analysis: OS X | Windows | Linux

As part of my MBA program, I’m required to take Written and Oral Communications. One of our assignments was to give a 10 minute persuasive speech on a topic of our choice. Given that I have an affinity towards technology, as well as being a computer engineer, I opted to write my speech on something in the technology field. After discussing the potential topics with my professor, I decided to analyze OS X, Windows and Ubuntu Linux, and persuade my class that OS X is the dominant and best operating system on the market.

Although this was given as a speech, I compiled the content in a document to prepare myself, and figured I would share it on here. Additionally, to aid with the delivery of the speech, I created a powerpoint presentation. The speech first looks at the growth of OS X’s market share from 2005 to 2011, and then analyzes several key components of the three operating systems and the company’s behind them.

In reality, its probably closer to a 13-15 minute speech with all of the components. For the sake of time during the actual presentation, due to the audience, the sections on security and underlying code were removed.

Any comments, questions, or suggestions, leave a message below – I’d be more than happy to discuss my position on this topic further with anyone who has a different opinion.

Downloads: Speech | Presentation

OS X | Windows | Linux

Marc Budofsky
Binghamton University, MGMT 516

Many factors affect a user’s decision in choosing what kind of computer to buy. One of the largest deciding factors for many users is the Operating System the computer will be running.

In recent years, Apple OS X’s ease of use and clean layout, combined with the visual appeal of the hardware and integration with Apple’s other products, has led to an increase in OS X’s market share and popularity, ultimately separating it from Windows and Linux as the best operating system available.

In 2005, OS X had a market share of only 3.05%. During this time, Apple had both the iBook and PowerBook on the market, running PowerPC processors and OS X 10.4 “Tiger”. The following year, Apple transitioned from PowerPC to Intel CPUs, and introduced the Macbook and Macbook Pro. Since the Apple-Intel Transition, Apple has released three updated versions of OS X, each offering additional features, functionality and speed-ups. Both the transition to Intel CPUs and the regular updates to OS X have helped to increase notebook sales, with OS X market share reaching 8.13% this year, and Apple recording record global market shares this past September. While this seems like a small increase, one must remember that the market share is based on all computers currently in use; Windows systems that have been in use since 2005 will still be reflected in the 2011 market share, skewing the data slightly.

In the process of determining which Operating System is best, an analysis of certain components of the OS and developer must be conducted. These components range from visual appeal and features that the user will interact with to key components that dictate how the OS will behave.

One of the most important components of the OS that the user will interact with is the pure aesthetics of the system; strictly how the screen looks and displays content to allow the user to quickly and easily perform their desired task.

OS X’s main interaction for users is a dock system; applications can be placed in the dock to allow quick execution, with all open applications residing in the dock as well. Additionally, the ability to make use of multiple desktops allows users to increase their productivity under OS X.

Windows uses a task bar as the main point of user interaction. In Windows 7, users can ‘pin’ applications to this task bar, similar to the ability of placing applications in the OS X dock, while all running applications are showed here as well. Windows 7 also makes use of a glass effect, allowing the user to view windows that are hidden due to other windows lying on top of them.
Ubuntu 11.04 allows users to customize the user interface. By default, it makes use of a task bar that is similar to that of Windows; the difference lies in that only running programs are displayed in the task bar. However, users have the ability to add a dock and multiple desktops by changing settings and through Compiz, a 3D effects application that is installed with the system.

Users typically look at the features that the OS will offer them after finding the look that most appeals to them. While there are many features that are common to all three operating systems, there are several that help to set them apart.

OS X incorporates many features that aim to further user productivity and ensure system stability. Some of the most notable features include Time Machine, an automated backup system that helps recover the system if a catastrophic error occurs, Versions and Autosave, a new set of features in Lion that allows a user to view revisions of their files and take portions from previous copies as they see necessary, Resume, which automatically reloads any applications and files that were previously opened if the system must be restarted, iCloud, a new service that allows a user to synchronize up to 5 GB of data across multiple computers, and Full Screen Applications, allowing the user to utilize the entire viewing area to help minimize distractions.

Windows too has features that are meant to increase productivity; Taskbar Preview allows the user to hover over a minimized window to view the contents, Libraries help organize folders and files that share similar content and allow the user one-click access, and Snap Windows automatically sizes and places windows based on where the user drags the window.

Ubuntu’s features are slightly different than that of the other two operating systems. Due to the open source nature of Ubuntu, its main features focus around its ability to allow the user to tweak and customize the system to their liking. By default, Ubuntu utilizes the GNOME desktop manager, but can be changed to either KDE or Xcfe. Additionally, Ubuntu is the only of the three to offer a version customized strictly for the netbook architecture, taking into account the small screen size and limited resources of the system.

Once a user has determined the features that are important to them, they will usually begin to install their applications on the computer.

OS X offers the simplest installation method out of the three; applications are typically installed via “drag and drop”, with no restarts required to finish the process. OS X also utilizes an App Store that allows users to purchase programs without having to leave their computer. For users that require programs that are designed for Windows, an emulation layer can be installed to allow these programs to run within OS X.

The installation process in Windows varies drastically from that of OS X. All programs are installed through dialogs, often requiring several clicks to proceed through the menus, and many times requiring a system restart to complete the installation. This becomes tedious for a user that wishes to install a large number of programs at once, as they will be waiting for the system to shut down and restart for extended periods of time.

In Ubuntu, there are two ways by which a user can install applications – building them via source code in terminal or through the Synaptic Package Manager. The Synaptic Package Manager operates in a fashion similar to the Mac App Store, while building applications from source requires a user to enter specific commands in the terminal and ensure that the necessary dependencies are installed on their system. Much like OS X, Ubuntu also allows Windows programs to be run by installing an emulation layer.

In addition to the components of the operating system that the user interacts with, there are many background tasks and functions that the user may never see, but play an important part in the overall system. The security and stability of the operating system is an important factor that must be considered during operation.

Due to its relatively small market share compared to Windows, OS X faces minimal virus threats. The few incidents that have been reported typically stem from users trying to obtain software through illegal means, and, for the most part, only affect a small portion of users. OS X does face several security issues due to the nature of how the system is set up, specifically related to User and Hardware-level security. By default, OS X creates profiles with administrative privileges; if a hacker compromises an administrative profile, the entire system is at their disposal. This can be remedied by changing the accounts to “user”-level, with a single administrative account being present and only used when needed. Security issues with regards to hardware become apparent when the system is booted off of an OS X install disc; if the system has no firmware password, a hacker can make changes to administrative passwords or partitions and disks.

Windows has notoriously been a target for viruses due to its market share. For a hacker, there is much more recognition in writing a program for Windows, as it has the potential of reaching more users. Due to this, Windows is a very virus prone operating system. While changes in applications and systems permissions have helped to reduce the number of viruses, Windows is still the leader in the number of infections. Another security issue was inadvertently introduced with Windows Vista. Microsoft implemented “User Account Control” as a way to limit programs from gaining administrative, or “superuser”, privileges without first being authorized by the user. While this seemed like a logical way to reduce administrative processes, the UAC was too intrusive and slowed down various tasks, including software installation. Because of this, many users disabled the UAC entirely, allowing any process to gain administrative privileges.

Linux has an even smaller market share than OS X, and, due to this, very few viruses are written to infect Linux systems. As such, Ubuntu has had minimal virus threats in its history. Additionally, due to the secure nature in which Ubuntu was created, it is often used to clean Windows systems that have been infected by a virus.

Most users are content knowing that their system works, not how it works. However, the underlying code of the operating system is important in determining how various tasks and processes will be handled. Three kernel architectures are currently used in operating systems: monolithic kernels, microkernels, and hybrid kernels. The different designs specify how the software and hardware will interact, and which parts of the operating system will be responsible for which tasks.

OS X utilizes a hybrid kernel based on the mach microkernel from Unix/BSD. A hybrid kernel allows the OS to split tasks between kernel space and user space, reducing the time it takes to perform certain operations. It is closed source with open source components due to the underlying Unix core. By implementing the Unix core, OS X benefits from many of the core functionality present in Unix and Linux systems.

Windows 7 also uses a hybrid kernel based on the NT kernel, which was developed by Microsoft for the Windows NT operating system. As such, the NT kernel is proprietary and only utilized by Microsoft in their operating systems.

Ubuntu makes use of a monolithic kernel. Unlike OS X and Windows 7, the monolithic kernel utilized by Ubuntu maintains all operating system functions in kernel space. The Linux Kernel is completely open source, and is used in the majority of Linux distributions.

One of the fastest growing uses of the computer is for software development; programming has contributed a large part to the fast-paced evolution of computing.

OS X can support most languages natively due to the inclusion of Terminal from the underlying Unix core. Terminal allows users to interact with the system via sets of specific commands, ultimately providing the necessary tools to compile and execute custom code.

Windows 7 has no out of the box support for any programming languages. One must install an additional software package to use Windows as a development environment. Two of the most common programs are Cygwin, a terminal clone, and Visual Studio, an integrated development environment.

Ubuntu, like OS X, has Terminal, and thus supports the majority of modern languages without any additional software.

Another factor that is important in determining which operating system is best is to look at the integration of the company producing the software. A more integrated company can help ensure better compatibility and a better user experience.

Apple is a completely integrated company. Looking beyond OS X, they design the hardware and software for all of their products. By having a hands-on approach through every step of the product development cycle, Apple is able to ensure the highest level of system compatibility throughout all of their product offerings. This applies to Apple’s desktop/notebook computers and OS X, as well as their iPhone/iPad and iOS.

Windows 7 is developed by Microsoft, and implemented by third party companies who develop the hardware. This approach will work as long as the hardware companies follow the strict requirements put in place by Microsoft. If they deviate, it could result in a poor user experience as the system will not be compatible. One benefit from this approach is that a user has the opportunity to design and build their own system.

Ubuntu is maintained by the Ubuntu Foundation, and licensed under the GNU General Public License. Although uncommon, it can sometimes be found installed by third party hardware manufacturers. Typically it is installed as an alternative OS to what comes on the system, or is added as a secondary OS to supplement the original OS.

The final factor that must be analyzed is the support that the developer offers for the OS.

Due to Apple’s integration approach, OS X has the best support. When a problem arises, the user simply has to make an appointment at their local Apple store and bring their computer in to the Genius Bar. Regardless of where the product was purchased, Apple will provide support as long as there is a valid warranty on the device. If a user desires additional support, they can purchase AppleCare, which provides full coverage, minus user error, for three years. There is also an active online community that operates via forums that can provide support for smaller issues.

Support for a Windows system can be more difficult to obtain. Due to the nature in which Windows computers can be purchased, a user may not know where to go to receive the appropriate help. Often times, one is able to call the manufacturer, but sometimes it is necessary to return to the seller. The worst case scenario occurs when the manufacturer and seller contradict each other, and inform the user that they need to obtain support from the other party. As with OS X, there is also an online community that operates in a similar fashion to offer help.

Ubuntu releases are generally supported for a six month cycle after release, due to the six month release cycle on updates. Basic support can be found on Ubuntu’s website, while the majority of information is located in various user forums and wikis.

Ultimately, there are many factors that need to be assessed to determine which operating system is truly best. While Windows and Ubuntu are strong performers, they fall short in several key areas and end up leaving the user wanting more from the system. OS X combines the key factors into a finely crafted package that provides the necessary tools for the most basic user up to the hardcore enthusiast. As computing continues to evolve, OS X will continue to eat away at the market share of Windows and further itself as the dominant OS.

Posted in: Binghamton University, Linux, OS X, Personal, Windows by Marc Budofsky 2 Comments

Thank You Box.net!

For anyone using an iPhone, download Box.net immediately on your phone and make an account. They’re running a new promotion and are offering 50 GB accounts for free, for life, with no strings attached. Easily the best cloud storage promotion I’ve ever seen.

20111013-191029.jpg

Posted in: iPhone Update, Miscellaneous by Marc Budofsky No Comments

Shareaholic SexyBookmarks Plugin

In an effort to make my blog more social networking friendly, I decided to install SexyBookmarks by Shareaholic to easily allow users to share any of my posts on some of the more popular sites – Facbeook, Twitter, StumbleUpon, LinkedIn, Reddit, Del.icio.us and via Email. Its an extremely easy plugin to configure, and hopefully some more traffic will be generated by using it. Anyway, just wanted to post about the addition of this plugin quickly. Check back in the coming weeks for updates on my projects and life – I know I’ve been making a lot of posts lately, but that might slow down a little as classes start to reach midterm time and the work starts to build up more.

Posted in: Miscellaneous by Marc Budofsky No Comments

Bringing Media By MRB into HTML5

Keeping with the trend I started last week of updating my resume, I decided an update of my portfolio was in order as well. From the same site where I found the layout for my resume, I found another tutorial for a portfolio utilizing HTML5 and jQuery.

Unlike the update to my resume, this one took a little more time and customization of the tutorial. In the end, the only part I didn’t modify was the underlying javascript to switch the current view, making changes to the header, content, and footer. The end result is a single page that dynamically alters the current view based on which selection the user has clicked. I also implemented another page for code to keep it all in one place, unlike before where I had a separate page for each class. I’m still in the process of tweaking the final few things, but I’ve moved my portfolio over to it already. Head over to the link to test it out, or check out the screenshot below.

Posted in: Personal, Web Design by Marc Budofsky No Comments

HTML5 / Schema: marcbudofsky.com

I’ve mean procrastinating updating my personal/resume site for the past couple of months. Last night, I finally sat down and updated the content, but was disappointed in the layout. Yes, I designed the site myself, but that was a year ago. Since then, my tastes and abilities have changed slightly, so I figured a redesign was in order. I had planned on designing something myself, but happened across this article last night while playing on my iPad. Of the tutorials listed, one was for a resume – How to Create an HTML5 Microdata Powered Resume. I saved the link and came back to it this morning. I originally planned on only playing around with it, but ended up implementing the entire layout already and moving marcbudofsky.com over to it already.

The overall layout is extremely clean, and by implementing all of the Schema tags, Google can dynamically change the content snippet shown when someone searches. This is helpful as it will hopefully broaden my presence on Google. Additionally, the entire site is done in HTML5. Check out the screenshot below, or head over to the live site here.

I think the next project will be a redesign of my portfolio. Stay tuned.

UPDATE: So I was a little premature in posting this – I’ve modified the code a bit to make it a little more ‘techy’. I’ve implemented a shuffle letters function found here on my name. The end result is that my name shuffles through several letters before finally displaying ‘Marc Budofsky’. Enjoy.

Posted in: Personal, Web Design by Marc Budofsky 1 Comment

Your University Maps

Welcome to Part 3 of my Google Maps API implementation. In my last post I explained how to implement the ability to save and load a set of data points via a JSON string on top of the Google Maps API as a set of markers and a polyline, and how to perform Dijkstra’s Shortest Path Algorithm with the resulting graph to create a point to point path for an indexed university.

When making the move from binghamtonumaps.com to yourniversitymaps.com I realized that a more automated process was needed when indexing a new campus. In addition to the automated process, I needed to clean up the polyline to accurately reflect the connections between markers on the map.

The first step in automating the process was to create various markers for each step of the process. To allow the user to differentiate markers, buildings are designated with purple markers, entrances/exits with blue markers and walkways with red markers. Furthermore, when connecting the points, the first marker selected is changed to a white marker to allow the user to visualize which marker has been selected.

The polyline has been corrected by using an array to store the coordinates, rather than dumping each longitude and latitude point into an ever-growing list of poly-coordinates. This allows the user to accurately see the connections that have been made, even when returning to the site after a period of being away.

Unfortunately, due to the continued development of youruniversitymaps.com, I will not be posting to the code that was developed to implement the automation of the indexing process. The code is a combination of php to query the database that stores much of the information, specifically the progress, javascript to handle the listeners that allow the placement of markers on the map, and AJAX to query an additional php script to load the coordinates that have already been placed by the user and saved on the server. Obviously, HTML and CSS are used to handle the rendering of the page and ensure a clean display for the user.

One function that I will explain that is used across all of the pages on youruniversitymaps.com is the resizing of the content to always fit within the available display window. In the development of the site, I came to the conclusion that I never wanted to see a scrollbar present on the site. This meant that whether the site was being on a 27″ monitor or a 10″ netbook, the content needed to be resized to properly fit the window. By utilizing the ‘viewport’ property of the browser, I was able to determine the size of the screen and adjust these values to find the necessary height and width of the various elements. For the implementation on youruniversitymaps.com, the only variables that needed to be changed were the height of both the sidebar and map. Additionally, the margin-top of the map element needed to be modified as the sidebar height was changed. Below you’ll find the function that handles the resizing of the page. In addition to calling the function when the page is loaded (via the onload method of the body tag), the function is called whenever the page size is modified.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$(window).resize(function() {
  setHeight();
});
 
function setHeight() {
  var viewportwidth; var viewportheight;
 
  if (typeof window.innerWidth != 'undefined') {
    viewportwidth = window.innerWidth; viewportheight = window.innerHeight;
  } else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0) {
    viewportwidth = document.documentElement.clientWidth; viewportheight = document.documentElement.clientHeight;
  } else {
    viewportwidth = document.getElementsByTagName('body')[0].clientWidth; viewportheight = document.getElementsByTagName('body')[0].clientHeight;
  }
 
  var sbH = viewportheight;
  var mcH = viewportheight;
  var mcT = 0;
  if ($('.browserChrome')[0]) {
    sbH -= 106; mcH -= 106; mcT = 96 - viewportheight;
  } else if ($('.browserFirefox')[0]) {
    sbH -= 104; mcH -= 100; mcT = 78 - viewportheight;
  } else if ($('.browserSafari')[0]) {
    sbH -= 115; mcH -= 117; mcT = 87 - viewportheight;
  }
  $('#leftSidebar').css('height', sbH);
  $('#map_canvas').css('height', mcH);
  $('#map_canvas').css('margin-top', mcT);
}

This code requires the jQuery plugin to be included on the page in order to properly set the appropriate css elements in the last few lines of code. If you want to use this in a project of your own, you will most likely need to modify the if statements to subtract the necessary values. While implementing this code on youruniversitymaps.com, I calculated the total space that my header and footer occupied, and then subtracted that from the viewportheight as appropriate.

If you’ve found these last few posts interesting and want to get involved with youruniversitymaps.com, please head over to the site and click on the link in the left sidebar. You will be presented with a contact form that will allow you to sign up to index your own school. Once you’ve been approved to index your school, you will get to witness first hand the automated process that was developed to streamline the indexing process, and you can brag to your friends about how you’ve made their lives easier in helping everyone at your school get across campus. As always, any comments or questions, please leave a message below. Additionally, if you’ve found any of these Google Maps API posts informative, please help spread them via stumbleupon/twitter/redit/etc.

Posted in: Javascript, PHP, Programming, Tutorial, Web Design by Marc Budofsky No Comments

Google Maps API, Part 2

In my last post, I explained the basic implementation of the Google Maps API to allow a previously unindexed set of points to be mapped out. After completing the first version of the code, I immediately noticed a few small bugs that hindered its operation – specifically, the ability to save and load previously selected points.

To enable saving and loading, an AJAX call was needed to query a PHP script. In short, the script would either take a JSON string and store it in a text file when saving, or take the contents of the text file and return it as a JSON string when loading. Saving is a much shorter process, as the data only needs to be dumped into the text file. Loading, on the other hand, requires that the data be parsed from the JSON string back into the correct format, and then all of the markers and lines be placed back on the map. In this iteration of the code, the line created among points when the data is loaded does not resemble any usable information to the user – this was addressed in the current version of the code later on.

Below, you’ll find the two functions that call the PHP script, and the PHP script itself. You can check out a usable copy here. In the demo, you’ll also notice that there is an option to copy the longitude/latitude coordinates of the buildings for later use, and to calculate the distances between markers present on the map.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
$('#saveA').click(function() {
  $.ajax({
    type: 'POST',
    url: 'nodes_save.php',
    data: {
      func : "save",
      fname : prompt("File Name:"),
      JSON : JSON.stringify(A)
    },
    dataType: 'json',
    success : function(data){
      $('#returnA').html("Data saved successfully");
      $('#containerA').show();
    }
  });
  $('#containerA').delay(2000).fadeOut('slow');
});
 
$('#loadA').click(function() {
  $.ajax({
    type: 'POST',
    url: 'nodes_save.php',
    data: {
      func : "load",
      fname : prompt("File Name:")
    },
    dataType: 'json',
    success : function(data){
      // Remove all Markers from Map
      for (var bar = 0; bar < markers.length; bar++) {
        var foo = markers[bar].getTitle();
        markers[bar].setMap(null);
        for (var baz = 0; baz < polyCoordinates.length; baz++) {
          if (polyCoordinates[baz] == foo) {
            polyCoordinates.splice(baz, 1);
            baz = 0;
          }
        }
      }
      // Update Polyline
      if (polyLine != undefined) polyLine.setMap(null);
      polyLine = new google.maps.Polyline({
        path: polyCoordinates,
        strokeColor: "#FF0000",
        strokeOpacity: 1.0,
        strokeWeight: 2
      });
      polyLine.setMap(map);
      // Delete values currently in A
      for (var qux in A) delete A[qux];
 
      // Load new values into A
      A = JSON.parse(data.d);
 
      // Reset cnt
      cnt = 0;
 
      // Load new values into markers
      for (var qux in A) {
        var coord = qux.toString().replace('(', '');
        coord = coord.replace(')', '');
        var c = coord.split(',');
        var pos = new google.maps.LatLng(c[0], c[1]);
        markers.push(new google.maps.Marker({
          position: pos, 
          map: map,
          draggable: false,
          title: qux
        }));
        google.maps.event.addListener(markers[cnt],'click', (function(cnt) { 
          return function() { 
            if (mode == 0) {
              var foo = markers[cnt].getTitle();
              // Remove Marker
              markers[cnt].setMap(null);
              // Delete array in A
              delete A[markers[cnt].getTitle()];
              // Delete entries in A and polyCoordinates, if any
              for (var baz = 0; baz < polyCoordinates.length; baz++) {
                if (polyCoordinates[baz] == foo) {
                  polyCoordinates.splice(baz, 1);
                  baz = 0;
                }
              }
              for (var qux in A) {
                for (var baz = 0; baz < A[qux].length; baz++) {
                  if (A[qux][baz] == foo) {
                    A[qux].splice(baz, 1);
                    baz = 0;
                  }
                }
              }
              // Update Polyline
              if (polyLine != undefined) polyLine.setMap(null);
              polyLine = new google.maps.Polyline({
                path: polyCoordinates,
                strokeColor: "#FF0000",
                strokeOpacity: 1.0,
                strokeWeight: 2
              });
              polyLine.setMap(map);
            } else if (mode == 1) {
              // If Marker already selected, remove selection
              if (markers[cnt].getIcon() == "http://itouchmap.com/i/blue-dot.png") {
                markers[cnt].setIcon(null);
                markers[cnt].setShadow(null);
                first ? endPt = -1 : startPt = -1;
                first = first ? false : true;
              } else {
                // Select Marker
                markers[cnt].setIcon("http://itouchmap.com/i/blue-dot.png");
                first ? startPt = cnt : endPt = cnt;
                first = first ? false : true;
              }
              // If 2 Markers selected, add to A and update Polyline
              if (startPt != -1 && endPt != -1) {
                // Check if relation has already been entered
                if ($.inArray(markers[endPt].getTitle(), A[markers[startPt].getTitle()]) == -1) {
                  // Add to A in appropriate locations
                  A[markers[startPt].getTitle()].push(markers[endPt].getTitle());
                  A[markers[endPt].getTitle()].push(markers[startPt].getTitle());
                  // Create Polyline
                  var foo = new google.maps.LatLng(markers[startPt].getPosition().lat(), markers[startPt].getPosition().lng());
                  if ($.inArray(markers[startPt].getTitle(), polyCoordinates) == -1)
                    polyCoordinates.push(foo);
                  var bar = new google.maps.LatLng(markers[endPt].getPosition().lat(), markers[endPt].getPosition().lng());
                  if ($.inArray(markers[endPt].getTitle(), polyCoordinates) == -1)
                    polyCoordinates.push(bar);
                  if (polyLine != undefined) polyLine.setMap(null);
                  polyLine = new google.maps.Polyline({
                    path: polyCoordinates,
                    strokeColor: "#FF0000",
                    strokeOpacity: 1.0,
                    strokeWeight: 2
                  });
                  polyLine.setMap(map);
                }
                // Reset Markers to Default
                markers[startPt].setIcon(null);
                markers[endPt].setIcon(null);
                // Reset Variables
                startPt = -1; endPt = -1;
              }
            } else if (mode == 2) {
              if ($.inArray(markers[cnt].getTitle(), buildings) == -1) {
                buildings.push(markers[cnt].getTitle())
              }
            }
          }; 
        })(cnt));
        cnt++;
      }
 
      // Recreate Polyline
      for (var qux in A) {
        for (var bar = 0; bar < A[qux].length; bar++) {
          var coord = qux.toString().replace('(', '');
          coord = coord.replace(')', '');
          var c = coord.split(',');
          var pos = new google.maps.LatLng(c[0], c[1]);
          polyCoordinates.push(pos);
 
          if (polyLine != undefined) polyLine.setMap(null);
          polyLine = new google.maps.Polyline({
            path: polyCoordinates,
            strokeColor: "#FF0000",
            strokeOpacity: 1.0,
            strokeWeight: 2
          });
          polyLine.setMap(map);
        }
      }
 
      $('#returnA').html("Data loaded successfully");
      $('#containerA').show();
    }
  });
  $('#containerA').delay(2000).fadeOut('slow');
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  if (isset($_POST['func']) && $_POST['func'] == "save") {
    $data = str_replace('\"', '"', $_POST['JSON']);
    $file_name = $_POST['fname'];
    file_put_contents($file_name, $data, LOCK_EX);
    $return['error'] = false;
    $return['msg'] = "Data saved successfully";
 
    echo json_encode($return);
  } elseif (isset($_POST['func']) && $_POST['func'] == "load") {
    $return['error'] = false;
    $return['d'] = file_get_contents($_POST['fname']);
 
    echo json_encode($return);
  }

The final step to getting the site to work was to implement Dijkstra’s Algorithm for shortest path. I used the pseudocode on Wikipedia as a starting point, and implemented it in Javscript.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function dijkstraPath() {
  var dist = {};
  var previous = {};
 
  for (var key in ptGraph) {
    dist[key] = Infinity;
    previous[key] = undefined;
  }
  dist[startNode] = 0;
  createQ();
  while (Q.length != 0) {
    var u = sortDist(dist);
    if ((dist[u] == Infinity) || (u == endNode) || (u == "")) break;
    removeU(u);
    for (var foo = 0; foo < ptGraph[u].length; foo++) {
      var v = ptGraph[u][foo];
      var alt = dist[u] + distance[u][foo];
      if (alt < dist[v]) {
        dist[v] = alt;
        previous[v] = u;
      }
    }
  }
  var S = [];
  while (previous[u] != undefined) {
    S.push(u);
    u = previous[u];
  }
  S.push(startNode);
  createMarker(startNode); createMarker(endNode);
  polyCoordinates.length = 0;
  for (var bar = 0; bar < S.length; bar++) createLine(S[bar]);
      }
 
function sortDist(dist) {
  var foo = Infinity;
  var ret = "";
  for (var bar = 0; bar < Q.length; bar++) {
    if (dist[Q[bar]] < foo) {
      foo = dist[Q[bar]];
      ret = Q[bar];
    }
  }
  return ret;
}
 
function removeU(u) {
  for (var foo = 0; foo < Q.length; foo++) {
    if (Q[foo] == u) {
      Q.splice(foo, 1);
      break;
    }
  }
}

After getting all of this working, I decided on the name ‘binghamtonumaps.com‘, and set up the site. I quickly realized that in designing the backend code the way I did, this site did not have to be limited to Binghamton University. Rather, any school could be set up as long as it was indexed properly. While the code for setting up the underlying graph made sense to me, I knew that it would need to be more automated if other people were going to be setting up their own schools. At the same time, I realized that binghamtonumaps.com was no longer an appropriate name given the new scope, and moved over to youruniversitymaps.com. Any questions/comments, leave a message below – I’ll save the final version writeup for the next post.

Google Maps API, Part 1

When I returned to Binghamton University at the beginning of this semester, I was immediately confronted by large amounts of construction in the middle of campus. Binghamton has been doing construction for the past 2 years, so this wasn’t that much of a surprise. However, with the construction being directly in the area of what used to be highly traveled walking paths, students and faculty were being forced to walk through other buildings to get to certain parts of campus. I’ll be honest, it took me a few days to figure out how to get around, even after being here for 4 years.

On Tuesdays and Thursdays, I have class from 2:50-5:50, a quick 10 minute break, and then another class at 6. By the time I get out of the first classes, I’m usually pretty hungry and make a run for the dining hall. In the first 2 weeks of the semester, this quick run to the dining hall meant showing up 5-10 minutes late to my 6:00 class. While making the move to get food 2 weeks ago, I was discussing with a friend in my class the quickest way to get to our next class. After quickly thinking about our options, we ended up picking a route and hoping for the best. At the same time, we joked about how nice it would be to have a website that would provide you with the quickest way to get from Point A to Point B on campus.

The next day I decided to give it a shot – I mean, the worst thing that could have happened was I tried to implement something and it wouldn’t work. Best case scenario, I develop a great new tool for Binghamton University students. I looked up the Google Maps API and quickly plugged in the latitude/longitude coordinates for several buildings on campus. I put all of the necessary code in place, selected my start point and end point, and was immediately disappointed with the results. Google only indexed the roads around campus – there were no paths on their map to go through the walkways in the middle. This meant that every route the map returned required you to walk around the edge of campus, even if the buildings were located in the middle.

After explaining to my friend Alex what I was trying to do, he helped me put together a rough idea of what would need to be done to get the map working the way I wanted it to. In short, I would need to index the middle of campus myself, and then use an algorithm to create the shortest path. Ultimately, I would only be using the Google Maps API for the picture of the map.

To make the process of indexing the middle of campus easier, I had to put together another page using the API. This page would have to have drastically different options than my first page that was just going to show the map. The basic functionality is as follows:

  1. Click on the map to place a marker – either a building, entrance/exit, or walkway via point – and at the same time add this location into a javascript object with an array attached to it. For instance, A[point1] = new Array(). This was necessary for creating a mapping of connected points, which was to come later.
  2. Each marker also had to have a click event attached to it. If it was clicked while in mode 0, the marker would have to be removed, as well as any references to it in the data structures. If it was clicked while in mode 1, it would have to be stored in memory until a second marker was clicked, at which point a connection was made between them, and again the necessary data structures were updated.

With the basic modes in place, I began putting everything together. Below you’ll find the javascript necessary to perform the operations as outlined above. If you don’t really care about the code, check out the live demo here.

?View Code JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>
<html>
  <head>
    <!-- Information -->
    <meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1' />
    <!-- Stylesheets -->
    <link href="http://code.google.com/apis/maps/documentation/javascript/examples/default.css" rel="stylesheet" type="text/css" />
    <style>
      .left { float: right; width: 120px; }
      .clear { clear: both; }
    </style>
    <!-- Javascript -->
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript" src="jquery.iphone-switch.js"></script>
    <script type="text/javascript" src="json2.js"></script>
    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript">
      var map;
      var markers = [];
      var A = {};
      var cnt = 0;
      var mode = 0; // 0 for Entering Points, 1 for Creating Graph
      var startPt = -1;
      var endPt = -1;
      var first = true;
      var polyCoordinates = [];
      var polyLine;
      var buildings = new Array();
 
      function initialize() {
        var binghamtonU = new google.maps.LatLng(42.088889,-75.966929);
        var myOptions = {
          zoom:17,
          mapTypeId: google.maps.MapTypeId.HYBRID,
          center: binghamtonU
        }
 
        map = new google.maps.Map(document.getElementById('map_canvas'), myOptions);
 
        google.maps.event.addListener(map,'click',function(event) {
          var title = event.latLng.toString();
          var pos = new google.maps.LatLng(event.latLng.lat(), event.latLng.lng());
          markers.push(new google.maps.Marker({
            position: pos, 
            map: map,
            draggable: false,
            title: title
          }));
          A[title] = new Array();
          google.maps.event.addListener(markers[cnt],'click', (function(cnt) { 
            return function() { 
              if (mode == 0) {
                var foo = markers[cnt].getTitle();
                // Remove Marker
                markers[cnt].setMap(null);
                // Delete array in A
                delete A[markers[cnt].getTitle()];
                // Delete entries in A and polyCoordinates, if any
                for (var baz = 0; baz < polyCoordinates.length; baz++) {
                  if (polyCoordinates[baz] == foo) {
                    polyCoordinates.splice(baz, 1);
                    baz = 0;
                  }
                }
                for (var qux in A) {
                  for (var baz = 0; baz < A[qux].length; baz++) {
                    if (A[qux][baz] == foo) {
                      A[qux].splice(baz, 1);
                      baz = 0;
                    }
                  }
                }
                // Update Polyline
                if (polyLine != undefined) polyLine.setMap(null);
                polyLine = new google.maps.Polyline({
                  path: polyCoordinates,
                  strokeColor: "#FF0000",
                  strokeOpacity: 1.0,
                  strokeWeight: 2
                });
                polyLine.setMap(map);
              } else {
                // If Marker already selected, remove selection
                if (markers[cnt].getIcon() == "blue-dot.png") {
                  markers[cnt].setIcon(null);
                  first ? endPt = -1 : startPt = -1;
                  first = first ? false : true;
                } else {
                  // Select Marker
                  markers[cnt].setIcon("blue-dot.png");
                  first ? startPt = cnt : endPt = cnt;
                  first = first ? false : true;
                }
                // If 2 Markers selected, add to A and update Polyline
                if (startPt != -1 && endPt != -1) {
                  // Check if relation has already been entered
                  if ($.inArray(markers[endPt].getTitle(), A[markers[startPt].getTitle()]) == -1) {
                    // Add to A in appropriate locations
                    A[markers[startPt].getTitle()].push(markers[endPt].getTitle());
                    A[markers[endPt].getTitle()].push(markers[startPt].getTitle());
                    // Create Polyline
                    var foo = new google.maps.LatLng(markers[startPt].getPosition().lat(), markers[startPt].getPosition().lng());
                    if ($.inArray(markers[startPt].getTitle(), polyCoordinates) == -1)
                      polyCoordinates.push(foo);
                    var bar = new google.maps.LatLng(markers[endPt].getPosition().lat(), markers[endPt].getPosition().lng());
                    if ($.inArray(markers[endPt].getTitle(), polyCoordinates) == -1)
                      polyCoordinates.push(bar);
                    if (polyLine != undefined) polyLine.setMap(null);
                    polyLine = new google.maps.Polyline({
                      path: polyCoordinates,
                      strokeColor: "#FF0000",
                      strokeOpacity: 1.0,
                      strokeWeight: 2
                    });
                    polyLine.setMap(map);
                  }
                  // Reset Markers to Default
                  markers[startPt].setIcon(null);
                  markers[endPt].setIcon(null);
                  // Reset Variables
                  startPt = -1; endPt = -1;
                }
              }
            };
          })(cnt));
          cnt++;
        });
      }
    </script>
  </head>
  <body onload="initialize()">
     <span style='font-size: 28px; font-family: Verdana,sans-serif; margin-left: 20px;'><a href='#' id='showA' style='color: #000;'>Done?</a></span>
     <div id='containerA' style='display: none; position: absolute; left: 50%; top: 100px; width: 800px; margin-left: -400px; z-index: 10000; background: #FFF; border: 3px solid #000; -moz-border-radius: 8px; -webkit-border-radius: 8px;'>
       <div id='returnA' style='margin-left: 20px;'></div>
     </div>
     <div class="left" id="opMode"></div>
     <div class="clear"></div>
 
     <script type="text/javascript">
       $('#opMode').iphoneSwitch("off", function() {
         mode = 1;
       },
       function() {
         mode = 0;
       },
       {
         switch_on_container_path: 'iphone_switch_container_off.png'
       });
 
       $('#showA').click(function() {
         $('#containerA').hide();
         var retA = JSON.stringify(A);
         retA += "<br><br><center><a href='#' onClick=\"$('#containerA').hide();\" style='color: #000;'>Close</a></center>";
         $('#returnA').html(retA);
         $('#containerA').show();
       });
     </script>
 
     <div id="map_canvas" style='top: 30px;'></div>
  </body>
</html>

After mapping out Binghamton using this page, I quickly realized that I had left out some crucial options necessary to use the data I was generating. Most importantly, I had no ability to save/load my data which meant that I would never be able to leave the page if I was still in the middle of finishing the map. This lead to version 2 of the code, which I’ll save for the next post. Any questions/comments, leave a message below.

Driving Around Virginia

I’m currently driving around Virginia (in the backseat) and realized that I am in desperate need of an update. Here’s a quick update to help pass the time as we drive:

1. I’m a college graduate. Yes, it’s a very crazy thought, but I am officially a computer engineer. Now all I need to do is finish up my MBA and get a job as an engineer for it to really be official.
2. I’m working at a tech day camp this summer, and recently taught myself Java. It’s extremely similar to C++. Like, almost the same language similar. It’ll be interesting once I actually start working to see if more kids pick C++ or Java.
3. WiseResume is up to about 125 users. Pretty cool considering we’re still constantly making changes. Hopefully that number increases a little more over the summer as people finish up internships/jobs and need feedback on them.

I’m sure there’s some stuff I meant to write about missing, but I’ll touch on it when I remember and I have my laptop in front of me. Until next time…

Posted in: Miscellaneous, Personal by Marc Budofsky No Comments

WiseResume in the News

As I posted last time, WiseResume is officially launched as an open beta. Since then, we’ve made some progress in the marketing department, and have had a few articles written about us:

Posted in: Wise Resume by Marc Budofsky No Comments