<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/camps/</id>
  <link href="https://www.endpointdev.com/blog/tags/camps/"/>
  <link href="https://www.endpointdev.com/blog/tags/camps/" rel="self"/>
  <updated>2019-02-05T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Camping in the Clouds with Terraform and Ansible</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/02/camping-in-the-clouds/"/>
      <id>https://www.endpointdev.com/blog/2019/02/camping-in-the-clouds/</id>
      <published>2019-02-05T00:00:00+00:00</published>
      <author>
        <name>Josh Williams</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/02/camping-in-the-clouds/image-0.jpg&#34; alt=&#34;Base Camp&#34; /&gt;&lt;br&gt;&lt;a href=&#34;https://www.flickr.com/photos/papalars/2773221431/&#34;&gt;Photo by Andrew E. Larsen&lt;/a&gt; · &lt;a href=&#34;https://creativecommons.org/licenses/by-nd/2.0/&#34;&gt;CC BY-ND 2.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Right, so, show of hands: How many of you work on some bit of web code by doing a &lt;code&gt;git clone&lt;/code&gt; to your own laptop, developing the feature or bug fix, running through manual testing of the app until you’re happy with it, and off it goes back up to the repo when done? I’m curious, and I have a few questions for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have you ever had a bit of code that worked locally, but didn’t in production because of some difference in systems, dependencies, or something else in the stack?&lt;/li&gt;
&lt;li&gt;How do you show off your work to a client or management for approval? Can you demo several alternate changes to the same site at the same time?&lt;/li&gt;
&lt;li&gt;How do you bring in coworkers to “look over your shoulder“ and help with something, especially ones that are far away?&lt;/li&gt;
&lt;li&gt;How do you get a new coworker up to speed if they’re doing development themselves?&lt;/li&gt;
&lt;li&gt;If you’re working on multiple things, do you create multiple clones?&lt;/li&gt;
&lt;li&gt;How’re your backups?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Are you fidgeting nervously thinking about that? Sorry. ☹ But also, check out this little thing: &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt;. It’s been an End Point staple for quite a while now, so if you’ve read our blog before you might have heard about it.&lt;/p&gt;
&lt;p&gt;Long story short: In addition to any local development you do, this system will spin up your own little environments (“camps”) on a remote development server. Each camp includes a checkout of the code, separate httpd/​nginx and app processes, and a dedicated database with a clone of the data. What’s that all mean?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Well, figuring that dev server is configured the same, you’ll be working right in a stack identical to production.&lt;/li&gt;
&lt;li&gt;Each camp gets its own port, so you can link your beautiful results to someone and they’ll see exactly what the site will look like when deployed.&lt;/li&gt;
&lt;li&gt;Bring coworkers in to a shared tmux session for code review or pair programming.&lt;/li&gt;
&lt;li&gt;And if they just can’t resist working on the same project they can create their own camp, without having to install dependencies and get the stack operational locally.&lt;/li&gt;
&lt;li&gt;Create multiple camps so you can work on new projects when in-​flight projects get put on the back burner.&lt;/li&gt;
&lt;li&gt;Those server backups your ops team promises are working will automatically preserve your work.&lt;/li&gt;
&lt;li&gt;And unicorns become real.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recently a client brought their app into “The Cloud.“ Kind of. No Kubernetes there, so I can’t use that coveted “k8s” blog post tag yet. It’s still a Java app sitting on a single big VM, but it’s still technically running in the cloud. So we used that opportunity to redo how this “campsite” works and made it cloudy, too. Each camp is a dedicated set of VMs that we spin up (and, for cost savings, shut down) as needed.&lt;/p&gt;
&lt;p&gt;We do that using &lt;a href=&#34;https://www.terraform.io/&#34;&gt;Terraform&lt;/a&gt;. We’re already using that for this client’s production systems. Terraform has a concept of &lt;a href=&#34;https://www.terraform.io/docs/state/workspaces.html&#34;&gt;workspaces&lt;/a&gt;, which basically clones your single set of systems and lets you apply that multiple times over. You can name the workspace pretty much anything, but we’ve stuck with the traditional camp method of just assigning numbers. Thus, each camp is a numbered workspace, with an identical VM for the app and an identical VM for the database. That gets handed over to Ansible for the same provisioning process.&lt;/p&gt;
&lt;p&gt;The configuration split is actually a little more complex than that. We have a ‘prod’ and a ‘dev’ module, which is mostly just different instance sizes. Then, combined with appropriate DNS naming parameters, ‘camp’, ‘staging’, and ‘prod’ configs. Just pull from those as needed. I’ll probably take you into that in more depth in a later post.&lt;/p&gt;
&lt;p&gt;But, instead of one big server which is a fixed cost no matter how many camps we’re running, each cloud camp adds to the cost only as long as it’s running. So, like I said above, shutting down the camps is a key point of this. We run them on smaller instances generally, but if you run a number of camps at once that cost adds up fast. Shutting down the camps when they’re not needed saves money. There’s a break-​even line somewhere in there, and I’ll leave calculating that as an exercise for the reader. But there are other benefits, too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On traditional camps running on a single system, they all share the same IP address and each gets its own port number. But running on multiple systems with multiple addresses you don’t have to worry about clients with odd egress firewalls that block traffic to nonstandard ports.&lt;/li&gt;
&lt;li&gt;Filesystem paths shouldn’t matter inside apps, but sometimes they do, and running camps in their own VMs means the apps can be deployed exactly where they are in production.&lt;/li&gt;
&lt;li&gt;Same with database ports: You get to talk to the system Postgres on its default port, and potentially even on a separate host.&lt;/li&gt;
&lt;li&gt;We tend to run our monolithic camp servers with SELinux disabled, but with cloud camps you can run with SELinux enforcing in staging environments just like in production.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloud camps take you the rest of the way there. You can feel like you’re working and testing right on production without &lt;em&gt;really&lt;/em&gt; feeling all that dirty about it. And, when you’re nearly done, you can control the resources assigned to the VMs, for example to switch the sizing configuration so that smaller VMs you use for development briefly become production-​sized for load testing. Briefly.&lt;/p&gt;
&lt;p&gt;I do love making things open source, but in this case I’m not sure there’s really anything to publish; it’s just the same Terraform configuration with just a little bit of tuning to make workspaces work better. But you’ve heard enough from me today, so I’ll write more about all those details later.&lt;/p&gt;
&lt;p&gt;There, I hope I’ve planted some ideas in your mind about how you can change that development methodology for the better. On the whole we work better collaboratively, and camp-​like systems for development can really assist that. It can feel weird and cumbersome at first, but the clients we have that have adopted it are generally happy campers.&lt;/p&gt;
&lt;p&gt;It’s still early on, but our cloud-​based camp experiment is showing lots of promise, too. Keep it in mind when you’re starting a development project.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>2015 Perl Dancer Conference videos</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/12/2015-perl-dancer-conference-videos/"/>
      <id>https://www.endpointdev.com/blog/2015/12/2015-perl-dancer-conference-videos/</id>
      <published>2015-12-30T00:00:00+00:00</published>
      <author>
        <name>Sam Batschelet</name>
      </author>
      <content type="html">
        &lt;p&gt;The 2015 &lt;a href=&#34;https://www.perl.dance&#34;&gt;Perl Dancer Conference&lt;/a&gt; has recently released the presentation videos. This year the conference was hosted in beautiful Vienna, Austria. Josh Lavin and I were both honored to attend the conference as well as give talks. Earlier, Josh wrote summaries of the conference:&lt;/p&gt;
&lt;h3 id=&#34;conference-recap&#34;&gt;Conference Recap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report/&#34;&gt;Training Days&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;/blog/2015/10/perl-dancer-conference-2015-report_30/&#34;&gt;Conference Days&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;conference-presentations&#34;&gt;Conference Presentations&lt;/h3&gt;
&lt;h4 id=&#34;spacecamps-the-final-frontier&#34;&gt;SpaceCamps “The Final Frontier”&lt;/h4&gt;
&lt;p&gt;I gave a talk exploring new technologies for End Point’s own &lt;a href=&#34;http://devcamps.org&#34;&gt;DevCamps&lt;/a&gt; development tool. During the presentation I detailed my research into containers and what a cloud-based development environment might look like.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=IYKs8FF8--Y&#34;&gt;SpaceCamps Presentation Video&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;angularjs--dancer-for-modern-web-development&#34;&gt;AngularJS &amp;amp; Dancer for Modern Web Development&lt;/h4&gt;
&lt;p&gt;Josh detailed his experience migrating legacy applications utilizing Dancer, AngularJS, and modern Perl techniques. Josh highlighted the challenges he faced during the process, as well as lessons he learned along the way.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=m7q6QbSHrkA&#34;&gt;AngularJS &amp;amp; Dancer for Modern Web Development Presentation Video&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;lightning-talks&#34;&gt;Lightning Talks&lt;/h3&gt;
&lt;p&gt;Josh and I both gave short “lightning talks.” Josh’s was on &lt;a href=&#34;https://youtu.be/-eg21qxxIAA?t=12m47s&#34;&gt;Writing Unit Tests for a Legacy App (Interchange 5)&lt;/a&gt;, and mine was on &lt;a href=&#34;https://youtu.be/-eg21qxxIAA?t=19m11s&#34;&gt;Plack &amp;amp; Interchange 5.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To review the rest of the presentations please checkout the &lt;a href=&#34;https://www.youtube.com/channel/UCWtnsx6yRuHvO2e-xX2Yyng&#34;&gt;Perl Dancer Conference YouTube channel&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;The Perl Dancer community continues to flourish and the conference this year hosted a record 5 core &lt;a href=&#34;http://perldancer.org&#34;&gt;Dancer&lt;/a&gt; developers. Dancer is about to release the finalized version of its long awaited plugin infrastructure for &lt;a href=&#34;https://github.com/PerlDancer/Dancer2&#34;&gt;Dancer2&lt;/a&gt;. A lot of work on this was completed during the conference. Being an organizer of the conference, it brings me great joy to see this success. This news along with the release of Perl 6, I am certain 2016 will be a wonderful year for not only Dancer but the entire &lt;a href=&#34;https://www.perl.org/&#34;&gt;Perl&lt;/a&gt; community.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Handling databases in dev environments for web development</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/04/handling-databases-in-dev-environments/"/>
      <id>https://www.endpointdev.com/blog/2015/04/handling-databases-in-dev-environments/</id>
      <published>2015-04-21T00:00:00+00:00</published>
      <author>
        <name>Spencer Christensen</name>
      </author>
      <content type="html">
        &lt;p&gt;One of the biggest problems for web development environments is copying large amounts of data.  Every time a new environment is needed, all that data needs to be copied.  Source code should be tracked in version control software, and so copying it should be a simple matter of checking it out from the code repository.  So that is usually not the problem.  The main problem area is database data.  This can be very large, take a long time to copy, and can impact the computers involved in the copy (usually the destination computer gets hammered with IO which makes load go high).&lt;/p&gt;
&lt;p&gt;Often databases for development environments are created by copying a database dump from production and then importing that database dump.  And since database dumps are text, they can be highly compressed, which can result in a relatively small file to copy over.  But the import of the dump can still take lots of time and cause high load on the dev computer as it rebuilds tables and indexes.  As long as your data is relatively small, this process may be perfectly acceptable.&lt;/p&gt;
&lt;h3 id=&#34;your-database-will-get-bigger&#34;&gt;Your database WILL get bigger&lt;/h3&gt;
&lt;p&gt;At some point though your database will get so big that this process will take too long and cause too much load to be acceptable.&lt;/p&gt;
&lt;p&gt;To address the problem you can try to reduce the amount of data involved by only dumping a portion of the database data instead of all of it, or possibly using some “dummy sample data” instead.  These techniques may work if you don’t care that development environments no longer have the same data as production.  However, one serious problem with this is that a bug or behavior found in production can’t be replicated in a development environment because the data involved isn’t the same.  For example, say a customer can’t checkout on the live site but you can’t replicate the bug in your development environment to fix the bug.  In this example, the root cause of the problem could be a bug in the code handling certain products that are out of stock, and since the dev database didn’t have the same data it could make finding and fixing these types of problems &lt;em&gt;a lot harder&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;snapshots&#34;&gt;Snapshots&lt;/h3&gt;
&lt;p&gt;Another option is to use file system snapshots, like LVM snapshots, to quickly make clones of the database without needing to import the database dump each time.  This works great if development environments live on the same server, or at least the development databases live on the same server.  You would need to create a volume to hold a single copy of the database; this copy would be the origin for all snapshots.  Then for each development environment, you could snapshot the origin volume, mount it read-write in a place accessible by the developer, customize the database configuration (like setting a unique port number to listen on), and then start up the database.  This then provides a clone of the entire database in a tiny fraction of the time and uses less disk space and other system resources too.&lt;/p&gt;
&lt;p&gt;In using snapshots there are some things you’ll need to be careful about.  Snapshots are usually created using copy-on-write tables.  The more snapshots mounted read-write, the more IO overhead is involved for the volumes involved.  For this reason it is important that writes to the origin volume be avoided as much as possible while the snapshots are open.  Also, snapshots that get a lot of writes can fill up their copy-on-write table, and depending on the file system and database that you are using this can be a big problem.  So it is important to monitor each open snapshot for how full it is and increase their size if needed so they don’t fill up.  Updating the origin database will require shutting down and removing all snapshots first, then update the origin database, then create and mount all the snapshots again.  This is because all the copy-on-write tables would get full if you tried to update the origin while the snapshots are open.&lt;/p&gt;
&lt;p&gt;Using snapshots like this may sound more complicated, and it is, but the processes involved can be scripted and automated and the benefits can be pretty significant if you have several developers and a lot of data to copy.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Looking at development environments with DevCamps and Vagrant</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/08/looking-at-development-environments/"/>
      <id>https://www.endpointdev.com/blog/2014/08/looking-at-development-environments/</id>
      <published>2014-08-25T00:00:00+00:00</published>
      <author>
        <name>Spencer Christensen</name>
      </author>
      <content type="html">
        &lt;p&gt;For most web developers, you have practices and tools that you are used to using to do your work. And for most web developers this means setting up your workstation with all the things you need to do your editing, compiling, testing, and pushing code to some place for sharing or deployment. This is a very common practice even though it is fraught with problems- like getting a database setup properly, configuring a web server, any other services (memcached, redis, mongodb, etc), and many more issues.&lt;/p&gt;
&lt;p&gt;Hopefully at some point you realize the pain that is involved in doing everything on your workstation directly and start looking for a better way to do web development. In this post I will be looking at some ways to do this better: using a virtual machine (VM), Vagrant, and DevCamps.&lt;/p&gt;
&lt;h3 id=&#34;using-a-vm-for-development&#34;&gt;Using a VM for development&lt;/h3&gt;
&lt;p&gt;One way to improve things is to use a local virtual machine for your development (for example, using VirtualBox, or VMware Fusion). You can edit your code normally on your workstation, but then execute and test it in the VM. This also makes your workstation “clean”, moving all those dependencies (like a database, web server, etc.) off your workstation and into the VM. It also gets your dev environment closer to production, if not identical. Sounds nice, but let’s break down the pros and cons.&lt;/p&gt;
&lt;h4 id=&#34;benefits-of-using-a-vm&#34;&gt;Benefits of using a VM&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Dev environment closely matches production.&lt;/li&gt;
&lt;li&gt;Execute and test code in a dedicated machine (not your workstation directly).&lt;/li&gt;
&lt;li&gt;Allows for multiple projects to be worked on concurrently (one VM per project).&lt;/li&gt;
&lt;li&gt;Exposes the developer to the Operations (systems administration) side of the web application (always a good thing).&lt;/li&gt;
&lt;li&gt;Developer can edit files using their favorite text editor locally on the workstation (but will need to copy files to the VM as needed).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;problems-with-using-a-vm&#34;&gt;Problems with using a VM&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Need to create and configure the VM. This could be very time consuming and error prone.&lt;/li&gt;
&lt;li&gt;Still need to install and configure all services and packages. This could also be time consuming and error prone.&lt;/li&gt;
&lt;li&gt;Backups of your work/configuration/everything are your own responsibility (extremely unlikely to happen).&lt;/li&gt;
&lt;li&gt;Access to your dev environment is extremely limited, thus probably only you can access it and test things on it. No way for a QA engineer or business owner to test/demo your work.&lt;/li&gt;
&lt;li&gt;Inexperienced developers can break things, or change them to no longer match production (install arbitrary packages, different versions than what is in production, screw up the db, screw up Apache configuration, etc.).&lt;/li&gt;
&lt;li&gt;If working with an established database, then downloading a dump, installing, and getting the database usable is time consuming and error prone. (“I just broke my dev database!” can be a complete blocker for development.)&lt;/li&gt;
&lt;li&gt;The developer needs to set up networking for the VM in order to ssh to it, copy files back and forth, and point a web browser to it. This may include manually setting up DNS, or /etc/hosts entries, or port forwarding, or more complex setups.&lt;/li&gt;
&lt;li&gt;If using SSL with the web application, then the developer also needs to generate and install the SSL cert and configure the web server correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;vagrant&#34;&gt;Vagrant&lt;/h3&gt;
&lt;p&gt;What is &lt;a href=&#34;https://www.vagrantup.com&#34;&gt;Vagrant&lt;/a&gt;? It is a set of tools to make it easier to use a virtual machine for your web development. It attempts to lessen many of the problems listed above through the use of automation. By design it also makes some assumptions about how you are using the VM. For example, it assumes that you have the source code for you project in a directory somewhere directly on your workstation and would prefer to use your favorite text editor on those files. Instead of expecting you to continually push updated files to your VM, it sets up a corresponding directory on the VM and keeps the two in sync for you (using either shared folders, NFS, Samba, or rsync). It also sets up the networking for accessing the VM, usually with port forwarding, so you don’t have to worry about that.&lt;/p&gt;
&lt;h4 id=&#34;benefits-of-vagrant&#34;&gt;Benefits of Vagrant&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;Same as those listed above for using a VM, plus&amp;hellip;&lt;/strong&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Flexible configuration (Vagrantfile) for creating and configuring the VM.&lt;/li&gt;
&lt;li&gt;Automated networking for the VM with port forwarding. Abstracted ssh access (don’t need to set up a hostname for the VM, simply type &lt;code&gt;vagrant ssh&lt;/code&gt; to connect). Port forwarded browser access to the VM (usually http://localhost:8080, but configurable).&lt;/li&gt;
&lt;li&gt;Synced directory between your workstation and the VM for source code. Allows for developers to use their favorite text editor locally on their workstation without needing to manually copy files to the VM.&lt;/li&gt;
&lt;li&gt;Expects the use of a configuration management system (like puppet, chef, salt, or bash scripts) to “provision” the VM (which could help with proper and consistent setup).&lt;/li&gt;
&lt;li&gt;Through the use of &lt;a href=&#34;https://vagrantcloud.com/&#34;&gt;Vagrant Cloud&lt;/a&gt; you can get a generated url for others to access your VM (makes it publicly available through a tunnel created with the command &lt;code&gt;vagrant share&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Configuration (Vagrantfile and puppet/chef/salt/etc.) files can be maintained/reviewed by Operations engineers for consistency with production.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;problems-with-vagrant&#34;&gt;Problems with Vagrant&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Still need to install and configure all services and packages. This is lessened with the use of a configuration management tool like puppet, but you still need to create/debug/maintain the puppet configuration and setup.&lt;/li&gt;
&lt;li&gt;Backups of your work/configuration/everything are your own responsibility (extremely unlikely to happen). This may be lessened for VM configuration files, assuming they are included in your project’s VCS repo along with your source code.&lt;/li&gt;
&lt;li&gt;Inexperienced developers can still break things, or change them to no longer match production (install arbitrary packages, different versions than what is in production, screw up the db, screw up Apache configuration, etc.).&lt;/li&gt;
&lt;li&gt;If working with an established database, then downloading a dump, installing, and getting the database usable is time consuming and error prone. (“I just broke my dev database!” can be a complete blocker for development.)&lt;/li&gt;
&lt;li&gt;If using SSL with the web application, then the developer also needs to generate and install the SSL cert and configure the web server correctly. This might be lessened if puppet (or whatever) is configured to manage this for you (but then you need to configure puppet to do that).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;devcamps&#34;&gt;DevCamps&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;http://devcamps.org&#34;&gt;DevCamps&lt;/a&gt; system takes a different approach. Instead of using VMs for development, it utilizes a shared server for all development. Each developer has their own account on the camps server and can create/update/delete “camps” (which are self-contained environments with all the parts needed). There is an initial setup for using camps which needs thorough understanding of the web application and all of its dependencies (OS, packages, services, etc.). For each camp, the system will create a directory for the user with everything related to that camp in it, including the web application source code, their own web server configuration, their own database with its own configuration, and any other resources. Each camp is assigned a camp number, and all services for that camp run on different ports (based on the camp number). For example, camp 12 may have Apache running on ports 9012 (HTTP) and 9112 (HTTPS) and MySQL running on port 8912. The developer doesn’t need to know these ports, as tools allow for easier access to the needed services (commands like &lt;code&gt;mkcamp&lt;/code&gt;, &lt;code&gt;re&lt;/code&gt; for restarting services, &lt;code&gt;mysql_camp&lt;/code&gt; for access to the database, etc.).&lt;/p&gt;
&lt;p&gt;DevCamps has been designed to address some of the pain usually associated with development environments. Developers usually do not need to install anything, since all dependencies should already be installed on the camps server (which should be maintained by an Operations engineer who can keep the packages, versions, etc. consistent with production). Having all development on a server allows Operations engineers to backup all dev work fairly easily. Databases do not need to be downloaded, manually setup, or anything- they should be set up initially with the camps system and then running &lt;code&gt;mkcamp&lt;/code&gt; clones the database and sets it up for you. Running &lt;code&gt;refresh-camp --db&lt;/code&gt; allows a developer to delete their camp’s database and get a fresh clone, ready to use.&lt;/p&gt;
&lt;h4 id=&#34;benefits-of-devcamps&#34;&gt;Benefits of DevCamps&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Each developer can create/delete camps as needed, allowing for multiple camps at once and multiple projects at once.&lt;/li&gt;
&lt;li&gt;Operations engineers can manage/maintain all dependencies for development, ensuring everything is consistent with production.&lt;/li&gt;
&lt;li&gt;Backups of all dev work is easy (Operations engineer just needs to backup the camps server).&lt;/li&gt;
&lt;li&gt;Developer does not need to configure services (camp templating system auto-generates needed configuration for proper port numbers), such as Apache, nginx, unicorn, MySQL, Postgres, etc.&lt;/li&gt;
&lt;li&gt;SSL certificates can be easily shared/generated/installed/etc. automatically with the &lt;code&gt;mkcamp&lt;/code&gt; script. Dev environments can easily have HTTPS without the developer doing anything.&lt;/li&gt;
&lt;li&gt;Developers should not have permissions to install/change system packages or services. Thus inexperienced developers should not be able to break the server, other developer’s environments, install arbitrary software. Screwing up their database or web server config can be fixed by either creating a new camp, refreshing their existing one, or an Operations engineer can easily fix it for them (since it is on a central server they would already have access to, and not need to worry about how to access some VM who knows where).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;problems-with-devcamps&#34;&gt;Problems with DevCamps&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Since all camps live on a shared server running on different ports, this will not closely match production in that way. However, this may not be significant if nearly everything else does closely match production.&lt;/li&gt;
&lt;li&gt;Adding a new dependency (for example, adding mongodb, or upgrading the version of Apache) may require quite a bit of effort and will affect all camps on the server- Operations engineer will need to install the needed packages and add/change the needed configuration to the camps system and templates.&lt;/li&gt;
&lt;li&gt;Using your favorite text editor locally on your workstation doesn’t really work since all code lives on the server. It is possible to SFTP files back and forth, but this can be tedious and error prone.&lt;/li&gt;
&lt;li&gt;Many aspects of the Operations (systems administration) side of the web application are hidden from the developer (this might also be considered a benefit).&lt;/li&gt;
&lt;li&gt;All development is on a single server, which may be a single point of failure (if the camps server is down, then all development is blocked for all developers).&lt;/li&gt;
&lt;li&gt;One camp can use up more CPU/RAM/disk/etc. then others and affect the server’s load, affecting the performance of all other camps.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;concluding-thoughts&#34;&gt;Concluding Thoughts&lt;/h3&gt;
&lt;p&gt;It seems that Vagrant and DevCamps certainly have some good things going for them. I think it might be worth some thought and effort to try to meld the two together somehow, to take the benefits of both and reduce the problems as much as possible. Such a system might look like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Utilize vagrant commands and configuration, but have all VMs live on a central VM server. Thus allowing for central backups and access.&lt;/li&gt;
&lt;li&gt;Source code and configuration lives on the server/VM but a synced directory is set up (sshfs mount point?) to allow for local editing of text files on the workstation.&lt;/li&gt;
&lt;li&gt;VMs created should have restricted access, preventing developers from installing arbitrary packages, versions, screwing up the db, etc.&lt;/li&gt;
&lt;li&gt;Configuration for services (database, web server, etc.) should be generated/managed by Operations engineers for consistency (utilizing puppet/chef/salt/etc.).&lt;/li&gt;
&lt;li&gt;Databases should be cloned from a local copy on the VM server, thus avoiding the need to download anything and reducing setup effort.&lt;/li&gt;
&lt;li&gt;SSL certs should be copied/generated locally on the VM server and installed as appropriate.&lt;/li&gt;
&lt;li&gt;Sharing access to a VM should not depend on Vagrant Cloud, but instead should use some sort of internal service on the VM server to automate VM hostname/DNS for browser and ssh access to the VM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m sure there are more pros and cons that I’ve missed. Add your thoughts to the comments below. Thanks.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Proxy Nginx ports using a regular expression</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/03/nginx-port-number-proxy-regular/"/>
      <id>https://www.endpointdev.com/blog/2014/03/nginx-port-number-proxy-regular/</id>
      <published>2014-03-19T00:00:00+00:00</published>
      <author>
        <name>Brian Gadoury</name>
      </author>
      <content type="html">
        &lt;p&gt;I’m working on a big Rails project for Phenoms Fantasy Sports that uses the &lt;a href=&#34;https://rubygems.org/gems/activemerchant&#34;&gt;ActiveMerchant gem&lt;/a&gt; to handle &lt;a href=&#34;https://developers.dwolla.com/&#34;&gt;Dwolla&lt;/a&gt; payments. One of the developers, &lt;a href=&#34;/team/patrick-lewis/&#34;&gt;Patrick&lt;/a&gt;, ran into an issue where his code wasn’t receiving the expected postback from the Dwolla gateway. His code looked right, the Dwolla account UI showed the sandbox transactions, but we never saw any evidence of the postback hitting our development server.&lt;/p&gt;
&lt;p&gt;Patrick’s theory was that Dwolla was stripping the port number off the postback URL he was sending with the request. We tested that theory by using the &lt;a href=&#34;https://requestbin.com/&#34;&gt;RequestBin.com service&lt;/a&gt; for the postback URL, and it showed Dwolla making the postback successfully. Next, we needed to verify that Dwolla could hit our development server on port 80.&lt;/p&gt;
&lt;p&gt;I started Nginx on port 80 of our dev server and Patrick fired his Dwolla transaction test again. The expected POST requests hit the Nginx logfile. Suspicions confirmed. It looked like we would just have to work around the Dwolla weirdness by proxying port 80 to the port that Patrick’s development instance was running on. Then we’d need a way to make that work for the other developers’ instances on the dev. server, as well.&lt;/p&gt;
&lt;p&gt;Proxying a single port to another port with Nginx is easy, but that second requirement is a little more complicated. We did get a little lucky with this bit, however. We are using &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps.org “camps”&lt;/a&gt; for this project. DevCamps’ naming convention for a given development instance (AKA a “camp”) number uses a two digit camp number as the hostname and as part of the port number. For example, camp 42 would run on 42.camp.example.com:9042. (I bet you can already see where I’m going with this.)&lt;/p&gt;
&lt;p&gt;I tweaked the Nginx config for the port 80 instance to use a regex to capture the hostname (“42” in this case) from the server_name portion of the HTTP request. It then appends that to the full hostname/IP address and the first two digits of that camp’s port number. That made the proxy work for everyone’s camp. Finally, I updated the config to work with any URI under the /dwolla directory.&lt;/p&gt;
&lt;p&gt;We now have the following tidbit in our Nginx config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;server {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    # [SNIP unrelated config stuff]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server_name ~^(?&amp;lt;portname&amp;gt;\d\d)\.camp\.;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    location /dwolla {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proxy_pass        http://169.29.89.157:90${portname}$uri;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        proxy_set_header  X-Real-IP  $remote_addr;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As root, I ran &lt;code&gt;service nginx reload&lt;/code&gt; to pick up the new config changes. Now Nginx automagically proxies connections to specific ports based on the server’s hostname.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>The more the merrier? Not always...</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/02/the-more-merrier-not-always/"/>
      <id>https://www.endpointdev.com/blog/2014/02/the-more-merrier-not-always/</id>
      <published>2014-02-05T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;Recently we were working on an image manipulation function for a customer that used &lt;a href=&#34;https://www.imagemagick.org/script/index.php&#34;&gt;ImageMagick&lt;/a&gt;’s convert command. We had spent tons of time working on the program and the associated system that was going to use it. Everything was working fine. The whole system was nice and snappy. Great job everyone!&lt;/p&gt;
&lt;p&gt;Until we moved it into production where the page load times were 8 to 10 times slower than in our &lt;a href=&#34;http://www.devcamps.org&#34;&gt;camps&lt;/a&gt; development system &amp;hellip;&lt;/p&gt;
&lt;p&gt;We all sprang into action to try to figure out why the page load times were so slow now. We reviewed system settings, configuration files for the database and application, and anything else we could think of. We made sure the OS packages, ImageMagick version, and various other things were the same, and everything looked right. The production hardware has twice the RAM and 4 times the number of processors as development does. So what the heck is going on?&lt;/p&gt;
&lt;p&gt;To distract ourselves and hope for more insight, we tried to optimize the code a bit and while making it a bit better we were still 6 to 8 times slower than in development. We deactivated the section of the site overnight so we could sleep on it. Luckily this was a new product line so it wasn’t tragic to turn it off.&lt;/p&gt;
&lt;p&gt;The next morning while discussing, a co-worker mentioned that the larger number of processors in production could be relevant. At first I was a bit taken aback because this goes against everything we think about more being better. How could it be that having 4 times the number of processors was a bad thing?!&lt;/p&gt;
&lt;p&gt;Well, it turns out that ImageMagick is a threaded program and will use as many processors in parallel as it can to accomplish whatever task it is asked to do. In doing this instead of splitting up the convert over 8 processors, it was now splitting it up over 32 processors. The extra work it was taking to manage the work being split between those extra 24 processors actually greatly slowed down the processing work!&lt;/p&gt;
&lt;p&gt;Luckily ImageMagick respects an environment variable setting to limit the maximum number of threads it will use. We set the OMP_NUM_THREADS environment variable to 4, re-ran the code, and then it performed as expected in production. It could be set to more or less threads, but we found that was fine and aside from keeping performance high, it keeps this one process from dominating CPU usage while it is running.&lt;/p&gt;
&lt;p&gt;It was a very interesting riddle to solve so I figured I’d share it.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Ecommerce Innovation 2013</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/10/ecommerce-innovation-2013/"/>
      <id>https://www.endpointdev.com/blog/2013/10/ecommerce-innovation-2013/</id>
      <published>2013-10-16T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;Mark Johnson and I went to the &lt;a href=&#34;http://www.ecommerce-innovation.com/&#34;&gt;Ecommerce Innovation 2013&lt;/a&gt; conference in beautiful Hancock, NY. The event was hosted by Sam Batschelet of &lt;a href=&#34;http://www.westbranchresort.com/&#34;&gt;West Branch Resort&lt;/a&gt;. The conference was spread out over three days and was very well planned. We had plenty of time in between talks to mingle with the other people. All of the talks were very insightful and informative. I found the mixture of technology and marketing talks beneficial. I have already discussed some things with my clients that I learned.&lt;/p&gt;
&lt;h3 id=&#34;a-brief-overview-of-the-talks&#34;&gt;A brief overview of the talks&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Jure Kodzoman of &lt;a href=&#34;http://www.informa.si/&#34;&gt;Informa&lt;/a&gt; had two different subjects.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;His first talk was about Template::Flute which is a Perl based template system which is the default template for Interchange 6. It utilizes the use of html classes to figure out where to parse in the data returned from your Perl code. Overall it seems pretty straight forward to use.&lt;/li&gt;
&lt;li&gt;His second talk was about the current state of the new Interchange 6 demo store.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ana Kozole of Informa had a talk named “Remarketing with Banners” that was really informative.The base of this is to have the ability to show specific banners to visitors on different websites.  She discussed different remarketing techniques including creating specific lists based on different criteria like all visitors, people who got to the checkout page but didn’t checkout or people who used a coupon code etc. You can also use remarketing lists for search ads.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Luka Klemenc of Informa gave two talks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;He discussed some a CRM system that they had developed in house and some of the pros and cons.&lt;/li&gt;
&lt;li&gt;Luka gave us short talk about the ways to know whether or not your newsletter is effective.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Josh Lavin of &lt;a href=&#34;http://www.perusion.com&#34;&gt;Perusion&lt;/a&gt; talked about a new template for Interchange 5 called Strap which is based on &lt;a href=&#34;http://getbootstrap.com/2.3.2/&#34;&gt;Bootstrap&lt;/a&gt; version 2.3.2. With this new template they have created a bunch of page and url changes to make the stock Interchange much more SEO friendly. This also makes a few underlying changes like assuming the username to login would be your email address and creating a multiple page checkout.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mike Heins of Perusion gave us a brief history of Interchange and compared it to modern day frameworks like Dancer. He also gave us a brief overview of PCI compliance and how Interchange holds up. He introduced us to the features of the Perusion Payment Server which is a remote credit card processing system that helps with PCI compliance.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stefan Hornburg of &lt;a href=&#34;http://www.linuxia.de/&#34;&gt;LinuXia Systems&lt;/a&gt; discussed two different topics with us.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gave us an overview of where the Interchange 6 project currently is and where it’s going. He gave us some code samples of the way we can do simple things like add an item to the cart, fetch the subtotal of the cart and talk to the database.&lt;/li&gt;
&lt;li&gt;Stefan walked us through an integration he did for OpenERP with Interchange 5 using RPC::XML.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;/team/mark-johnson/&#34;&gt;Mark Johnson&lt;/a&gt; gave us a review of the modifications to Interchange 5 to allow web servers like &lt;a href=&#34;http://www.nginx.com&#34;&gt;nginx&lt;/a&gt; or &lt;a href=&#34;http://www.apache.org&#34;&gt;Apache&lt;/a&gt; to cache entire pages. He discussed how we modified Interchange 5 for a customer to help with a DDoS attack. He laid out all of the new usertags and directives you will need to set to get pages to be cachable including some “gotchas” like not sending cookie information if you want this page to be cached. We hope that this feature will be included in the Interchange 5.8.1 release.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sam Batschelet gave a talk about &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt; and the reasons why it is so great. He discussed things like using Perlbrew and Carton in camps to help get around the fact that most Linux operating systems ship with a pretty old version of Perl. He also expanded on a few features that we hope to get released soon.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last big item on the schedule was a 2 hour round table discussion about the database schema for Interchange 6. It was a very good discussion with many different opinions for adjustments. Most of us based our suggestions on past experience with clients. I do not think we are finished making adjustments to it but we are on the right path to a very flexible setup.&lt;/p&gt;
&lt;p&gt;Overall I thought the conference was a great success. It was great to meet in person some people I had only seen on a mailing list before and pass around ideas for the future. I cannot wait to see what cool new things we will have to discuss next year!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>eCommerce Innovation Conference 2013</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/09/ecommerce-innovation-conference-2013/"/>
      <id>https://www.endpointdev.com/blog/2013/09/ecommerce-innovation-conference-2013/</id>
      <published>2013-09-20T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;The &lt;a href=&#34;http://www.ecommerce-innovation.com/&#34;&gt;eCommerce Innovation Conference 2013&lt;/a&gt; is a new conference being held in Hancock, New York, between October 8th and 11th. The conference aims to discuss everything ecommerce with a focus on &lt;a href=&#34;http://www.perl.org/&#34;&gt;Perl&lt;/a&gt;-based solutions including &lt;a href=&#34;http://perldancer.org/&#34;&gt;Dancer&lt;/a&gt; and &lt;a href=&#34;http://www.icdevgroup.org/&#34;&gt;Interchange&lt;/a&gt;. It isn’t geared directly to any one specific type of person unlike most conferences. The current speakers list include in-house ecommerce software developers, consultants, sales managers, project managers, and marketing experts. The talk topics range from customer relationship management to template engines for Perl.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;/team/mark-johnson/&#34;&gt;Mark Johnson&lt;/a&gt; and I are both going to be speaking at the conference. Also there will be Mike Heins, creator of Interchange, and Stefan Hornburg, longtime Interchange development group “team captain”.&lt;/p&gt;
&lt;p&gt;Mark is going to be discussing full page caching in Interchange 5. This is becoming a more frequent request from our larger customers. They want to be able to do full page caching to allow the web browser and a caching proxy server alone to handle most requests leaving Interchange and the database open to handle more shopping-based requests like add to cart or checkout. This is a commonly-used architecture in many application servers, and my colleague David Christensen has several new features already in use by customers to make full-page caching easier, which are expected to go into Interchange 5.8.1 soon.&lt;/p&gt;
&lt;p&gt;I will be doing a talk on &lt;a href=&#34;http://www.icdevgroup.org/slides/eic2013/multi-site-setup/talk.html#&#34;&gt;multi-site setup in Interchange 5&lt;/a&gt;. This is a request we have received frequently over the years. Companies may either already have some kind of wholesale website or just want to have multiple websites use the same database and programming but allow for different website designs. They normally need to control what website a product will show up on and possibly adjust the price accordingly. I’ll discuss the different methods we have used to accomplish this at End Point.&lt;/p&gt;
&lt;p&gt;I see on the schedule that Sam Batschelet will be &lt;a href=&#34;http://www.icdevgroup.org/slides/eic2013/Camps.pdf&#34;&gt;speaking about the camps system&lt;/a&gt; and some new capabilities he’s added for &lt;a href=&#34;http://perlbrew.pl/&#34;&gt;perlbrew&lt;/a&gt; and &lt;a href=&#34;https://github.com/miyagawa/carton&#34;&gt;Carton&lt;/a&gt;, among other things. We are also using camps some places with perlbrew and &lt;a href=&#34;https://github.com/tokuhirom/plenv&#34;&gt;plenv&lt;/a&gt;, so it will be interesting to compare notes. I hope we’ll see some discussion and/or contribution to the &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;open source DevCamps&lt;/a&gt; project soon!&lt;/p&gt;
&lt;p&gt;It promises to be a very nice conference with lots of diverse information!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Git as rsync</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/02/git-as-rsync/"/>
      <id>https://www.endpointdev.com/blog/2013/02/git-as-rsync/</id>
      <published>2013-02-14T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;I had a quick-and-dirty problem to solve recently:&lt;/p&gt;
&lt;p&gt;The clients had uploaded many assorted images to a development &lt;a href=&#34;http://devcamps.org&#34;&gt;camp&lt;/a&gt;, but the .gitignore meant those updates were not picked up when we committed and pushed and rolled out to the live site. Normally, one would just rsync the files, but for various reasons this was not practical.&lt;/p&gt;
&lt;p&gt;So my solution, which I think can get filed under “Stupid ‘git’ tricks (as opposed to Tricks of a Stupid Git)”:&lt;/p&gt;
&lt;p&gt;(on the source repo)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git checkout -b images_update
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git add -f path-to-missing-images
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git commit -m &amp;#39;Do not push me! I&amp;#39;m just a silly temporary commit&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(“add -f” forces the images into the index, overriding our gitignore settings)&lt;/p&gt;
&lt;p&gt;(on the target repo)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git remote add images /path/to/source/repo
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git fetch
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git checkout -f images/images_update path-to-missing-images
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git remote rm images
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ git reset HEAD path-to-missing-images&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That last “git reset” is because the newly-restored images will be git-added by default, and we didn’t want them committed to the central repo.&lt;/p&gt;
&lt;p&gt;So what did we do here? For those dumbfounded by the level of silly, we used git to record the state of all the files in a certain path; then we pulled them back out into another location without disturbing anything already there. But as a benefit, we do have a record of what happened, in case we need to reproduce it.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Camp tools</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/01/camp-tools/"/>
      <id>https://www.endpointdev.com/blog/2013/01/camp-tools/</id>
      <published>2013-01-14T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;a href=&#34;http://www.devcamps.org/&#34;&gt;Devcamps&lt;/a&gt; are such a big part of my everyday work that I can’t imagine life without them. Over the years, I developed some short-cuts in navigating camps that I also can’t live without: I share them below.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function camp_top() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  if [ -n &amp;#34;$1&amp;#34; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      cd ~/camp${1}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  elif [[ $(pwd) =~ &amp;#39;camp&amp;#39; ]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      until [[ $(basename $(pwd)) =~ &amp;#39;^camp[[:digit:]]+&amp;#39; ]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      do
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          if [[ $(pwd) =~ &amp;#39;camp&amp;#39; ]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              cd ..
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          else
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              break
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          fi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      done
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fi
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias ct=&amp;#39;camp_top; pwd&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function cat_root() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  camp_top $*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cd catalogs/* &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias cr=&amp;#39;cat_root; pwd&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function pages_root() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cat_root $*
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  cd pages &amp;gt;/dev/null
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias pr=&amp;#39;pages_root; pwd&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;function what_camp() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  c=$( camp_top $* 2&amp;gt; /dev/null; basename $( pwd ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  echo $c
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(“cat_root” and “pages_root” are very &lt;a href=&#34;http://www.icdevgroup.org/i/dev&#34;&gt;Interchange&lt;/a&gt;-specific; you may find other short-cuts more useful in your particular camp.)&lt;/p&gt;
&lt;p&gt;There’s nothing terribly ground-breaking here, but if bash is not your native shell-tongue, then you might find these useful.&lt;/p&gt;
&lt;p&gt;What I do is to stash these somewhere like “$HOME/.bash_camps”, then alter my .bashrc:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# Source campy definitions
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;if [ -f ~/.bash_camps ]; then
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; . ~/.bash_camps
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s all it takes. Have you a camp-y shell script, function, or alias? Please share in the comments!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>DevCamps: Creating new camps from a non-default Git branch</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/08/devcamps-creating-new-camps-from-non/"/>
      <id>https://www.endpointdev.com/blog/2012/08/devcamps-creating-new-camps-from-non/</id>
      <published>2012-08-31T00:00:00+00:00</published>
      <author>
        <name>Brian Gadoury</name>
      </author>
      <content type="html">
        &lt;p&gt;I recently set up part of a new Rails project &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps installation&lt;/a&gt; with a unique Git repo setup and discovered a trick for creating camps from a Git branch other than master. Admittedly, the circumstances that led to me discovering this trick are a bit specific to this project, but the trick itself can be useful in other situations as well.&lt;/p&gt;
&lt;p&gt;The Git repo specified in local-config had a master branch with nothing in it but the standard &amp;ldquo;initial commit.&amp;rdquo; This relatively new project uses a simplifed &lt;a href=&#34;http://jeffkreeftmeijer.com/2010/why-arent-you-using-git-flow/&#34;&gt;git-flow workflow&lt;/a&gt; and as such, all its code was still in the &amp;ldquo;develop&amp;rdquo; branch.&lt;/p&gt;
&lt;p&gt;In my case, this empty-ish master branch meant there were no tracked files in &lt;strong&gt;CAMP_PATH&lt;/strong&gt;/public directory. This meant that Git did not create that directory when the repo is cloned by &lt;code&gt;mkcamp&lt;/code&gt;. This meant that apache2 would refuse to start. Camping without a web server makes my back hurt, so I snooped around a little bit&amp;hellip;&lt;/p&gt;
&lt;p&gt;I discovered two things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can tell &lt;code&gt;git clone&lt;/code&gt; which branch to checkout initially by passing it a &amp;lsquo;&amp;ndash;branch $your_non_default_branch&amp;rsquo; switch&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;mkcamp&lt;/code&gt; command will happily pass that switch (as well as any other spicy options you include) along to the &lt;code&gt;git clone&lt;/code&gt; system command it executes. To do that, just add it to your camp type&amp;rsquo;s local-config file as part of the &amp;lsquo;repo_path_git&amp;rsquo; config variable. For example:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;repo_path_git:git@github.com:somegituser/somegitrepo.git &amp;ndash;branch develop&lt;/p&gt;
&lt;p&gt;Note that this option means your fresh new camp won&amp;rsquo;t have a &amp;lsquo;master&amp;rsquo; branch checked out. This might confuse some users, but we all know the &amp;lsquo;master&amp;rsquo; branch is nothing but a tracking branch with some convention mixed in. A simple &lt;code&gt;git checkout master&lt;/code&gt; will create that expected master branch easily enough. It&amp;rsquo;s probably worth giving your devs a heads up about this, lest they think something wonky is afoot with mkcamp.&lt;/p&gt;
&lt;p&gt;Now, there are people out there that may try to find fault with my solution. These detractors, these misanthropes, these malingering sluggards might cry &amp;ldquo;Why don&amp;rsquo;t you just commit an empty &lt;strong&gt;CAMP_PATH&lt;/strong&gt;/public/.gitkeep&amp;rdquo; to your master branch?&amp;quot; Well, I like a clean git history. So, to those people I would say, &amp;ldquo;David, that&amp;rsquo;s messy and silly and wouldn&amp;rsquo;t make a very good blog article at all. I&amp;rsquo;m embarrassed for you for even bringing it up, &lt;em&gt;David.&lt;/em&gt;&amp;rdquo;&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>The Berkman Center projects</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/06/berkman-center-brian-gadoury-and-his/"/>
      <id>https://www.endpointdev.com/blog/2012/06/berkman-center-brian-gadoury-and-his/</id>
      <published>2012-06-13T00:00:00+00:00</published>
      <author>
        <name>Terry Grant</name>
      </author>
      <content type="html">
        &lt;p&gt;Brian Gadoury and his awesome socks gave a great and informative presentation on our client Berkman Center.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.flickr.com/photos/80083124@N08/7184120757/&#34; title=&#34;IMG_0738.JPG by endpoint920, on Flickr&#34;&gt;&lt;img alt=&#34;IMG_0738.JPG&#34; height=&#34;375&#34; src=&#34;/blog/2012/06/berkman-center-brian-gadoury-and-his/image-0.jpeg&#34; width=&#34;500&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Berkman Center’s mission is to explore and understand cyberspace; and to study its development, dynamics, norms and standards.&lt;/p&gt;
&lt;p&gt;Brian’s first project was called Zone One that is a document repository tool that houses all of the electronic documents for use by Harvard. You can search by document name, tags, and content. Zone One is written using open source technologies such as Ruby on Rails, Postgres, Solr, and &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The application includes an array of features that allow you to interact with the search results and the documents themselves. Each entry can have detailed meta-data associated with it, that can be referenced by future users.&lt;/p&gt;
&lt;p&gt;One of the nice features of Zone One is its upload feature. It allows you to drag and drop files into a section the form for upload. The upload interface also includes a very nice SFTP system that utilizes virtual users on the system you are uploading to, to manage the files being uploaded and connected to the entry you are creating.&lt;/p&gt;
&lt;p&gt;Phase two of the project will include features to export to external repositories, a bulk import feature, and an API.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>DevCamps setup with Ruby 1.9.3, rbenv, Nginx and Unicorn</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/02/devcamps-setup-with-ruby-193-rbenv/"/>
      <id>https://www.endpointdev.com/blog/2012/02/devcamps-setup-with-ruby-193-rbenv/</id>
      <published>2012-02-10T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;I was working with Steph Skardal on the setup of a new &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt; installation that was going to need to use &lt;a href=&#34;http://www.ruby-lang.org/en/&#34;&gt;Ruby 1.9.3&lt;/a&gt;, &lt;a href=&#34;http://rubyonrails.org/&#34;&gt;Rails 3&lt;/a&gt;, &lt;a href=&#34;http://unicorn.bogomips.org/&#34;&gt;Unicorn&lt;/a&gt; and &lt;a href=&#34;http://wiki.nginx.org/Main&#34;&gt;Nginx&lt;/a&gt;. This setup was going to be much different than a standard setup due to the different application stack that was required.&lt;/p&gt;
&lt;p&gt;The first trick for this was going to get Ruby 1.9.3 on the server. We were using Debian Squeeze but that still only comes with Ruby 1.9.1. We wanted Ruby 1.9.3 for the increased overall speed and significant speed increase with Rails 3. We decided on using &lt;a href=&#34;https://github.com/sstephenson/rbenv&#34;&gt;rbenv&lt;/a&gt; for this task. It’s a very easy to setup utility that allows you to maintain multiple version of Ruby in your system user account without the headache of adjusting anything but the PATH environment variable. It takes advantage of another easy to setup utility called &lt;a href=&#34;https://github.com/sstephenson/ruby-build&#34;&gt;ruby build&lt;/a&gt; to handle the actual installation of the Ruby source code.&lt;/p&gt;
&lt;p&gt;A quick and easy version for setting up a user with this is as follows:&lt;/p&gt;
&lt;p&gt;Ensure you are in the home directory. Then, clone the repository into a .rbenv directory&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone git://github.com/sstephenson/rbenv.git .rbenv&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Adjust your users path to find the newly installed commands&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &amp;#39;export PATH=$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH&amp;#39; &amp;gt;&amp;gt; ~/.bash_profile&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install Ruby version 1.9.3-p0&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rbenv install 1.9.3-p0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Make Ruby version 1.9.3-p0 your default version every time you log in&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rbenv global 1.9.3-p0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Install the bundler gem for Ruby version 1.9.3-p0&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem install bundler&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Refresh rbenv to let it know the new system command bundler exists&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rbenv rehash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you are ready to use the bundler gem to install any other gems required for the application.&lt;/p&gt;
&lt;p&gt;The normal camps setup assumes you are going to be using Apache for the web server. In this case, we wanted to use Nginx due to memory constraints. We decided to use the proxy capability and just proxy through to Unicorn instead of having to build our own version Nginx to use Passenger. To do this, we had to use a feature in the local-config file in camps that allows you to skip the Apache setup and use your own commands to start, stop and restart your web server and application.  Here is the example from our local-config that controlls Nginx and Unicorn. This approach could also be used with Interchange or any other application if you need other services started when mkcamp is run.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;skip_apache:1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd_start:/usr/sbin/nginx -c __CAMP_PATH__/nginx/nginx.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd_stop:pid=`cat __CAMP_PATH__/var/run/nginx.pid 2&amp;gt;/dev/null` &amp;amp;&amp;amp; kill $pid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;httpd_restart:pid=`cat __CAMP_PATH__/var/run/nginx.pid 2&amp;gt;/dev/null` &amp;amp;&amp;amp; kill -HUP $pid || /usr/sbin/nginx -c __CAMP_PATH__/nginx/nginx.conf
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app_start:__CAMP_PATH__/bin/start-app
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app_stop:pid=`cat __CAMP_PATH__/var/run/unicorn.pid 2&amp;gt;/dev/null` &amp;amp;&amp;amp; kill $pid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app_restart:pid=`cat __CAMP_PATH__/var/run/unicorn.pid 2&amp;gt;/dev/null` &amp;amp;&amp;amp; kill $pid ; sleep 5 ;  __CAMP_PATH__/bin/start-app&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The contents of the start-app script is simply.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd __CAMP_PATH__ &amp;amp;&amp;amp; bundle exec unicorn_rails -c __CAMP_PATH__/config/unicorn.conf.rb -D&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You could create one script that handles all aspects of start, stop and restart if you wanted. This setup really wasn’t much harder than a normal Ruby on Rails setup. The added time here required to set up rbenv per camp user is offset by the fact that users can manage and try multiple versions of ruby.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Running Integration Tests in WebKit Without a Browser</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2011/12/running-integration-tests-in-webkit/"/>
      <id>https://www.endpointdev.com/blog/2011/12/running-integration-tests-in-webkit/</id>
      <published>2011-12-08T00:00:00+00:00</published>
      <author>
        <name>Mike Farmer</name>
      </author>
      <content type="html">
        &lt;p&gt;As your ruby web applications increase in UI complexity, they get harder to test using the standard Cucumber or even RSpec integration test suites. This is because of introduction of JavaScript in your UI. You’ve probably been there before. Here’s the use case: You’ve written your integration tests for your Rails app and up to this point, you’ve been able to get away with not tagging your cucumber scenarios with the “@javascript” tag. Everything is going smoothly and then it’s time to implement that one UI feature that is going to require an Ajax call or some javascript to hide or unhide a crucial piece of the user experience. This &lt;strong&gt;must&lt;/strong&gt; be included in your integration tests.&lt;/p&gt;
&lt;p&gt;So you go through the pain of setting up cucumber to work with selenium and tag your scenario as javascript so that it will run the test in the browser. At first, there’s this thrill of excitement as you get to see Firefox load, and then run through a series of steps, executing your tests and then seeing them pass. Job done.&lt;/p&gt;
&lt;p&gt;But maybe there’s a different scenario at play here. What if you don’t do your development in an environment that has a browser? At End Point, we are strong advocates of doing development on the &lt;a href=&#34;http://www.devcamps.org/why&#34;&gt;same environment that your app is going to run on&lt;/a&gt;. It eliminates unexpected issues down the road. We believe in it so much, actually, that we’ve created &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt; that allows you to setup development environments on a server.&lt;/p&gt;
&lt;p&gt;Obviously, your selenium based tests are not going to work here without some work to get it to run headless.&lt;/p&gt;
&lt;p&gt;The good folks at &lt;a href=&#34;https://thoughtbot.com/&#34;&gt;thoughtbot&lt;/a&gt; have come up with a great solution to this and it is called &lt;a href=&#34;https://github.com/thoughtbot&#34;&gt;capybara-webkit&lt;/a&gt;. It assumes that you are using capybara for your testing framework. If you are using &lt;a href=&#34;https://github.com/brynary/webrat&#34;&gt;webrat&lt;/a&gt;, the transition is fairly smooth. You’ll probably only need to change a few minor details in your tests.&lt;/p&gt;
&lt;p&gt;What capybara-webkit does for you is enable you to run your tests inside of WebKit. This will simulate an environment that will be very close to what you would see in Google Chrome or Safari as well as many mobile browsers. I’ve found that except for some edge cases, it covers Firefox and IE as well.&lt;/p&gt;
&lt;p&gt;To install capybara-webkit you will need to install the Qt development toolkit. It’s fairly straight forward so I’ll just refer you to the &lt;a href=&#34;https://github.com/thoughtbot/capybara-webkit/wiki/Installing-QT&#34;&gt;github wiki&lt;/a&gt; page for instructions for the various platforms. In Ubuntu, I just ran the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install libqt4-dev&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you are installing on a server environment, you’ll also need to install Xvfb. You can do that in Ubuntu with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install xvfb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s a little outside the scope of this blog post to go into other little things you need to setup with xvfb. The important thing is that you set it up to run on display 99. Another important note, is that you don’t have to set it up to run on boot. We will be starting it up when we run our tests if it isn’t running.&lt;/p&gt;
&lt;p&gt;The next step is to configure your cucumber tests to use the capybara-webkit driver. To do that, add&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem &amp;#34;capybara-webkit&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;to your Gemfile in the development and test group. Then in your env.rb file for cucumber add the following lines:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Capybara.javascript_driver = :webkit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In some cases, I’ve found it helpful to also specify a server port and app_host as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Capybara.server_port = &amp;#39;8000&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Capybara.app_host = &amp;#39;http://localhost:8000&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now your tests are setup to run in WebKit. The final step is running the tests. To do this, you’ll need to run them from within xvfb. You can do that with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;xvfb-run bundle exec cucumber&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I’ve created an alias for this and dropped it in my .bashrc file. Here’s my entry, but you can set it up anyway you’d like.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias xcuke=&amp;#34;xvfb-run bundle exec cucumber&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now running tests is a simple as running xcuke from the root of my Rails application.&lt;/p&gt;
&lt;p&gt;There are a couple of big benefits to running capybara-webkit. First is speed. In my experience tests run much faster than they do in Selenium. Second, all JavaScript errors are dumped to STDOUT so you can see them in the output of your cucumber tests. Third, all of your tests are being run on WebKit instead of rack so you get a test environment that acts more like a real browser would behave.&lt;/p&gt;
&lt;p&gt;Thanks to the guys at thoughtbot for putting together this awesome gem.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Semaphore limits and many Apache instances on Linux</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2011/12/semaphore-limits-and-many-apache/"/>
      <id>https://www.endpointdev.com/blog/2011/12/semaphore-limits-and-many-apache/</id>
      <published>2011-12-07T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;On some of our development servers, we run many instances of the Apache httpd web server on the same system. By “many”, I mean 30 or more separate Apache instances, each with its own configuration file and child processes. This is not unusual on &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;DevCamps&lt;/a&gt; setups with many developers working on many projects on the same server at the same time, each project having a complete software stack nearly identical to production.&lt;/p&gt;
&lt;p&gt;On Red Hat Enterprise Linux 5, with somewhere in the range of 30 to 40 Apache instances on a server, you can run into failures at startup time with this error or another similar one in the error log:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[error] (28)No space left on device: Cannot create SSLMutex&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The exact error will depend on what Apache modules you are running. The “space left on device” error does not mean you’ve run out of disk space or free inodes on your filesystem, but that you have run out of SysV IPC semaphores.&lt;/p&gt;
&lt;p&gt;You can see what your limits are like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# cat /proc/sys/kernel/sem
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;250 32000 32 128&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I typically double those limits by adding this line to /etc/sysctl.conf:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kernel.sem = 500 64000 64 256&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That makes sure you’ll get the change at the next boot. To make the change take immediate effect:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# sysctl -p&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With those limits I’ve run 100 Apache instances on the same server.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>DevCamps news</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2011/08/devcamps-news/"/>
      <id>https://www.endpointdev.com/blog/2011/08/devcamps-news/</id>
      <published>2011-08-04T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;DevCamps is a system for managing development, integration, staging, and production environments. It was developed by End Point for, and with the help of, some of our ecommerce clients. It grew over the space of several years, and really started to become its own standalone project in 2007.&lt;/p&gt;
&lt;p&gt;Camps are a behind-the-scenes workhorse of our web application development at End Point, and don’t always get much attention because everyone’s too busy using camps to get work done! But this summer a few things are happening.&lt;/p&gt;
&lt;p&gt;In early July we unveiled a redesign of the devcamps.org website that features a more whimsical look, a better explanation of what camps are all about, and endorsements by business and developer users. Marko Bijelic of &lt;a href=&#34;http://hipinspire.com/&#34;&gt;Hipinspire&lt;/a&gt; did the design. Take a look:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.devcamps.org/&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5637232476222945378&#34; src=&#34;/blog/2011/08/devcamps-news/image-0.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;width: 400px; height: 338px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.devcamps.org/&#34;&gt;www.devcamps.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In less than two weeks, on August 17, I’m going to be giving a &lt;a href=&#34;https://web.archive.org/web/20110917034518/http://yapceurope.lv/ye2011/talk/3629&#34;&gt;talk on camps&lt;/a&gt; at YAPC::EU in Riga, Latvia. YAPC::EU is Europe’s annual Perl conference, and will be a nice place to talk about camps.&lt;/p&gt;
&lt;p&gt;Many Perl developers are doing web applications, which is camps’ main focus, so that’s reason enough. But camps also started around the &lt;a href=&#34;http://www.icdevgroup.org/i/dev&#34;&gt;Interchange&lt;/a&gt; application server, which is written in Perl. And the camp system is currently implemented in Perl as well.&lt;/p&gt;
&lt;p&gt;We’ve set up a lot of camp systems for Perl web applications. So even though we’ve also set up camp systems for web applications using Ruby on Rails, Sinatra, Django, and PHP, it’s a nice homecoming to talk about camps to Perl enthusiasts.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Using nginx to transparently modify/debug third-party content</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2011/02/using-nginx-to-transparently/"/>
      <id>https://www.endpointdev.com/blog/2011/02/using-nginx-to-transparently/</id>
      <published>2011-02-06T00:00:00+00:00</published>
      <author>
        <name>David Christensen</name>
      </author>
      <content type="html">
        &lt;p&gt;In tracking down a recent front-end bug for one of our client
sites, I found myself needing to use the browser’s JavaScript debugger
for stepping through some JavaScript code that lived in a mix of
domains; this included a third-party framework as well as
locally-hosted code which interfaced with—​and potentially
interfered with—​said third-party code. (We’ll call said code
foo.min.js for the purposes of this article.) The
third-party code was a feature that was integrated into the client
site using a custom domain name and was hosted and controlled by the
third-party service with no ability for us to change directly. The
custom domain name was part of a chain of CNAMEs which eventually
pointed to the underlying &lt;em&gt;actual&lt;/em&gt; IP of the third-party service, so
their infrastructure obviously relied on getting the Host
header correctly in the request to select which among many clients was
being served.&lt;/p&gt;
&lt;p&gt;It appeared as if there was a conflict between code on our site and
that imported by the third party service. As part of the debugging
process, I was stepping through the JavaScript in order to determine
what if any conflicts there were, as well as their nature (e.g.,
conflicting library definitions, etc.). Stepping through our code was
fine, however the third-party’s JS code was (a) unfamiliar, and (b)
minified, so this had the effect of putting all of the JavaScript code
more-or-less on one line, which made tracing through the code in the
debugger much less useful than I had hoped.&lt;/p&gt;
&lt;p&gt;My first instinct was to use a JavaScript beautifier to reverse the
minification process, but since I had no control over the code being
included from the third-party service, this did not seem to be
directly feasible. The third-party code was deployed only on our
production site and relied on hard-coded domains which would make
integrating it into one of our development instances challenging since
we had no control over the contents of the returned resources. Since
the relevant feature (and subsequent bugs) was only on the production
site, making extensive modifications to how things were done and
potentially breaking that or other features for users while I was
debugging was obviously out as an option.&lt;/p&gt;
&lt;p&gt;Enter nginx. I’ve been doing a lot with nginx lately as far as
using it as a reverse proxy cache, so it’s been on my mind lately. So
I came up with this technique:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Look up the IP address for the third-party’s domain name (used for later purposes).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install nginx on localhost, listening to port 80.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Modify /etc/hosts to point the third-party’s domain name to the nginx server’s IP (also localhost in this case).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure a new virtual host with the following logical constraints:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &amp;lt;ul&amp;gt;
   &amp;lt;li&amp;gt;We want to serve specific files (the beautified JavaScript) from our local server.
   &amp;lt;li&amp;gt;We want any other request going through that domain to be passed-through transparently, so neither the browser nor the third-party server treat it differently.
 &amp;lt;/ul&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Given these constraints, this is the minimal configuration that I came up with (the interesting parts are located in the server block):&lt;/p&gt;
&lt;p&gt;/etc/hosts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;example.domain.com 127.0.0.1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;nginx.conf:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;worker_processes 1;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;events {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    worker_connections 10;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;http {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    include       mime.types;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    default_type  application/octet-stream;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    server {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        server_name example.domain.com;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        root /path/to/local_root;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        try_files $uri @proxied;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        location @proxied {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            proxy_set_header Host $http_host;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            proxy_pass http://1.2.3.4;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once I had the above configured/setup, I downloaded/saved the
foo.min.js file from the third-party service, ran it through
a JS beautifier, and saved it in the local nginx’s cache root so it
would be served up instead of the actual file from the third-party
service. Any other requests for static resources (images, other
scripts, etc) would pass-through to the third-party server, so I had
my nicely-formatted JavaScript code to step through, the production site
worked as normal for anyone else despite potential local changes to
the file on my end (i.e., adding JavaScript alert() calls to the
file, and no one was the wiser.&lt;/p&gt;
&lt;h3 id=&#34;a-few-notes&#34;&gt;A few notes&lt;/h3&gt;
&lt;p&gt;The try_files directive instructs nginx to first look for
a file named after the current URI (foo.min.js in our
example) in our local cache, and if this is not found, then fallback
to the proxied location block; i.e., relay the request to the original
upstream server. We explicitly set the Host header on the
proxy request because we want the request to behave normally with
respect to name-based hosting, and provide the saved IP address to
contact the server in question.&lt;/p&gt;
&lt;p&gt;We only needed to preserve/lookup the upstream server’s IP address
because we’re running the nginx server on localhost, so if we used a
domain name the lookup would return the same IP defined in
/etc/hosts; if the nginx server was running on a different
machine, you would be able to just use the domain name as both the
server_name and the proxy_pass parameters and set
the entry for the host in your local /etc/hosts file to the
IP of the nginx server.&lt;/p&gt;
&lt;p&gt;A possible extension would be to detect when an upstream request
matched a minified URL (via a location ~ .min..*.js$
block) and automatically beautify/cache the content in our local
cache. This could be accomplished via the use of an external FastCGI
script to retrieve, post-process, and cache the content.&lt;/p&gt;
&lt;p&gt;This technique can also be used when dealing with testing changes
to a production site on which you are unable or unwilling to make
potentially disruptive changes for the purposes of testing static
resources. (JavaScript seems the most obvious application here, but this
could apply to serving up images or other static content which would
be resolvable by the local cache.)&lt;/p&gt;
&lt;p&gt;I always need to remind myself to undo changes to
/etc/hosts as soon as I’m done testing when using tricks like
these. Particularly in something like this which is more-or-less
transparent, the behavior would be functionaly identical as long as
code/scripts on the third-party site stayed the same, but could easily
introduce subtle bugs if the third-party services made changes to
their codebase. Since our local copies would mask any remote changes
for those non-proxied resources, this could be very confusing if you
forget that things are set up this way.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>DevCamps on different systems, including Plesk, CPanel and ISPConfig</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2010/01/devcamps-on-different-systems-including/"/>
      <id>https://www.endpointdev.com/blog/2010/01/devcamps-on-different-systems-including/</id>
      <published>2010-01-08T00:00:00+00:00</published>
      <author>
        <name>Ron Phipps</name>
      </author>
      <content type="html">
        &lt;p&gt;In the last few months I’ve been active setting up &lt;a href=&#34;http://www.devcamps.org&#34;&gt;DevCamps&lt;/a&gt; for several of our newer clients. DevCamps is an open source development environment system, that once setup, allows for easily starting up and tearing down a development environment for a specific site/code base.&lt;/p&gt;
&lt;p&gt;I’ve done many camps setups, and you tend to run into surprises from system to system, but what was most interesting and challenging about these latest installs was that they were to be done on systems running Plesk, CPanel, and ISPConfig. Some things that are different between a normal deployment and one on the above mentioned platforms are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;On the Plesk system there was a secured Linux called ‘Atomic Secured Linux’ which includes the grsecurity module. One restriction of this module is (TPE) Trusted Path Execution which required the camp bin scripts to be owned by root and the bin directory could not be writable by other groups, otherwise they would fail to run.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Permissions are a mixed bag, where typically we set all of the files to be owned by the site owner, in Plesk there are special groups such as psacln that the files need to be owned by.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the CPanel system we needed to move the admin images for Interchange to a different directory since CPanel includes Interchange and has aliases for /interchange/ and /interchange-5/ to point at a central location which we would not be using.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On ISPConfig and Plesk the home directories of the sites are in different places, which required deploying the code in such places as /var/www/clients/client/user/domain.com or /var/www/vhosts/domain.com.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the end we were able to get DevCamps to run properly on these various platforms both in development and production. If you are starting a new project or working on an existing project and could use a strong development environment, consider &lt;a href=&#34;http://www.devcamps.org&#34;&gt;DevCamps&lt;/a&gt;.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Subverting Subversion for Fun and Profit</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2009/04/subverting-subversion-for-fun-and/"/>
      <id>https://www.endpointdev.com/blog/2009/04/subverting-subversion-for-fun-and/</id>
      <published>2009-04-07T00:00:00+00:00</published>
      <author>
        <name>David Christensen</name>
      </author>
      <content type="html">
        &lt;p&gt;One of our clients recently discovered a bug in a little-used but vital portion of the admin functionality of their site. (Stay with me here&amp;hellip;) After traditional debugging techniques failed on the code in question, it was time to look to the VCS for identifying the regression.&lt;/p&gt;
&lt;p&gt;We fortunately had the code for their site in version control, which is obviously a big win. Unfortunately (for me, at least), the repository was stored in Subversion, which means that my bag o’ tricks was significantly diminished compared to my favorite VCS, git. After attempting to use &amp;lsquo;svn log/svn diff -c&amp;rsquo; to help identify the culprit based on what I &lt;em&gt;thought&lt;/em&gt; the issue might be, I realized that svn was just not up to the task.&lt;/p&gt;
&lt;p&gt;Enter git-svn. Using git svn clone file://path/to/repository/trunk, I was able to acquire a git-ized version of the application’s repository. For this client, we use &lt;a href=&#34;http://devcamps.org&#34;&gt;DevCamps&lt;/a&gt; exclusively, so the entire application stack is stored in the local directory and run locally, including apache instance and postgres cluster. These pieces are necessarily unversioned, and are ignored in the repository setup. I was able to stop all camp services in the old camp directory (svn-based), rsync over all unversioned files to the new git repository (excluding the .svn metadata), replace the svn-based camp with the new git-svn based one, and fire up the camp services again. Started up immediately and worked like a charm. I now had git installed and working in what had previously only been svn-capable before.&lt;/p&gt;
&lt;p&gt;Now that I had a git installation, I was able to pull one of my favorite tools from my toolbox when fighting regressions: git-bisect. In my previous svn contortions, I had located a previous revision several hundred commits back which did not exhibit the regression, so I was able to start the bisect with the following command: git bisect start &lt;em&gt;bad&lt;/em&gt; &lt;em&gt;good&lt;/em&gt;. In this case, bad was master and good was the revision I had found previously. Using git svn find-rev r&lt;em&gt;number&lt;/em&gt;, I found the SHA1 commit for the good ref as git saw it.&lt;/p&gt;
&lt;p&gt;From this point, I was able to quickly identify the commit which introduced the regression. In reviewing the diff, there was nothing that I would have expected to cause the issue at hand; the code did not touch any of the affected area of the admin. But git had never lied to me before. I compared the code currently in master with that introduced in the implicated commit and saw that most of it was still in place. I began selectively commenting out pieces of the code the commit introduced, and was able to enable/disable the bug with increasingly fine granularity. Finally, I was able to identify the single line which when removed caused the issue to evaporate. This was a line in an innocuous template which had a simple variable interpolation (inside an HTML comment, nonetheless); however, this line (which was in a file which was included with every document, added in the implicated commit) revealed a bug in the parser of the app-server which was causing the symptoms in the unrelated admin area.&lt;/p&gt;
&lt;p&gt;It’s certain that I would never have been able to find the source of this issue without git-bisect, as manual bisection with svn would have been too tedious to even consider. I am able to happily interact with the rest of the development team with git being my secret weapon; git svn dcommit enables me to push my commits upstream, and git svn fetch/git svn rebase enable me to pull in the upstream changes. I’ll never need to tell my subversive secret (except, you know, on the company blog), and my own happiness and productivity has increased. Profit!!11 all around.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Camps presentation at UTOSC 2008</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2008/08/camps-presentation-at-utosc-2008/"/>
      <id>https://www.endpointdev.com/blog/2008/08/camps-presentation-at-utosc-2008/</id>
      <published>2008-08-31T00:00:00+00:00</published>
      <author>
        <name>Jon Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;Friday evening I did a presentation on and demonstration of our “development camps” at the &lt;a href=&#34;https://web.archive.org/web/20080901001212/http://2008.utosc.com/pages/home/&#34;&gt;2008 Utah Open Source Conference&lt;/a&gt; in Salt Lake City. Attendees seemed to get what camps are all about, asked some good questions, and we had some good conversations afterwards. You can read my &lt;a href=&#34;https://web.archive.org/web/20080901001218/http://2008.utosc.com:80/presentation/81/&#34;&gt;presentation abstract&lt;/a&gt; and &lt;a href=&#34;http://www.devcamps.org/camps-presentation-20080829/&#34;&gt;my slides and notes&lt;/a&gt;, and more will be coming soon at the &lt;a href=&#34;http://www.devcamps.org/&#34;&gt;camps website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’ll post more later on some talks I attended and enjoyed at the conference.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
