diff --git a/django/contrib/admin/media/js/inlines.js b/django/contrib/admin/media/js/inlines.js
index c45ce58..d969438 100644
--- a/django/contrib/admin/media/js/inlines.js
+++ b/django/contrib/admin/media/js/inlines.js
@@ -26,23 +26,13 @@
 		};
 		var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
 		var initialForms = $("#id_" + options.prefix + "-INITIAL_FORMS");
-		var maxForms = parseInt(totalForms.val());
+		var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS");
+		console.log(maxForms.val(), initialForms.val(), options.prefix);
 		// only show the add button if we are allowed to add more items
-		var showAddButton = (maxForms - parseInt(initialForms.val())) > 0;
+		var showAddButton = ((maxForms.val() == 0) || ((maxForms.val()-initialForms.val()) > 0));
 		var selectedItems = this;
 		$(this).each(function(i) {
 			$(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
-			// hide the extras, but only if there were no form errors
-			if (!$(".errornote").html()) {
-				var relatedItems = $(selectedItems).not("." + options.emptyCssClass);
-				extraRows = relatedItems.length;
-				if (parseInt(initialForms.val()) >= 0) {
-					$(relatedItems).slice(initialForms.val()).remove();
-				} else {
-					$(relatedItems).remove();
-				}
-				totalForms.val(parseInt(initialForms.val()));
-			}
 		});
 		if ($(this).length && showAddButton) {
 			var addButton;
@@ -58,9 +48,8 @@
 				addButton = $(this).filter(":last").next().find("a");
 			}
 			addButton.click(function() {
-				var totalForms = parseInt($("#id_" + options.prefix + "-TOTAL_FORMS").val());
-				var initialForms = parseInt($("#id_" + options.prefix + "-INITIAL_FORMS").val());
-				var nextIndex = totalForms + 1;
+				var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
+				var nextIndex = parseInt(totalForms.val()) + 1;
 				var template = $("#" + options.prefix + "-empty");
 				var row = template.clone(true).get(0);
 				$(row).removeClass(options.emptyCssClass).removeAttr("id").insertBefore($(template));
@@ -79,10 +68,14 @@
 					// last child element of the form's container:
 					$(row).children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
 				}
+				$(row).find("input,select,textarea,label").each(function() {
+					updateElementIndex(this, options.prefix, totalForms.val());
+				});
 				// Update number of total forms
-				$("#id_" + options.prefix + "-TOTAL_FORMS").val(nextIndex);
-				// Hide add button in case we've hit the max
-				if (maxForms <= nextIndex) {
+				$(totalForms).val(nextIndex);
+				// Hide add button in case we've hit the max, except we want to add infinitely
+				console.log(maxForms.val(), totalForms.val())
+				if ((maxForms.val() != 0) && (maxForms.val() <= totalForms.val())) {
 					addButton.parent().hide();
 				}
 				// The delete button of each row triggers a bunch of other things
@@ -96,7 +89,8 @@
 					var forms = $("." + options.formCssClass);
 					$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
 					// Show add button again once we drop below max
-					if (maxForms >= forms.length) {
+					console.log(maxForms.val(), forms.length);
+					if ((maxForms.val() == 0) || (maxForms.val() >= forms.length)) {
 						addButton.parent().show();
 					}
 					// Also, update names and ids for all remaining form controls
@@ -108,9 +102,6 @@
 					}
 					return false;
 				});
-				$(row).find("input,select,textarea,label").each(function() {
-					updateElementIndex(this, options.prefix, totalForms);
-				});
 				// If a post-add callback was supplied, call it with the added form:
 				if (options.added) options.added($(row));
 				return false;
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 9dfdb8b..4e3cfdc 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1193,7 +1193,7 @@ class InlineModelAdmin(BaseModelAdmin):
 
     def _media(self):
         from django.conf import settings
-        js = ['js/jquery.min.js', 'js/inlines.min.js']
+        js = ['js/jquery.min.js', 'js/inlines.js']
         if self.prepopulated_fields:
             js.append('js/urlify.js')
         if self.filter_vertical or self.filter_horizontal:
diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index a86c18f..58af0ac 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -12,6 +12,7 @@ __all__ = ('BaseFormSet', 'all_valid')
 # special field names
 TOTAL_FORM_COUNT = 'TOTAL_FORMS'
 INITIAL_FORM_COUNT = 'INITIAL_FORMS'
+MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS'
 ORDERING_FIELD_NAME = 'ORDER'
 DELETION_FIELD_NAME = 'DELETE'
 
@@ -24,6 +25,7 @@ class ManagementForm(Form):
     def __init__(self, *args, **kwargs):
         self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
         self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
+        self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(widget=HiddenInput)
         super(ManagementForm, self).__init__(*args, **kwargs)
 
 class BaseFormSet(StrAndUnicode):
@@ -56,7 +58,8 @@ class BaseFormSet(StrAndUnicode):
         else:
             form = ManagementForm(auto_id=self.auto_id, prefix=self.prefix, initial={
                 TOTAL_FORM_COUNT: self.total_form_count(),
-                INITIAL_FORM_COUNT: self.initial_form_count()
+                INITIAL_FORM_COUNT: self.initial_form_count(),
+                MAX_NUM_FORM_COUNT: self.max_num
             })
         return form
     management_form = property(_management_form)
