docs: function(el, hookupOptions) {
                      // Setup values passed to component
                      var initalScopeData = {},
                          component = this,
                          twoWayBindings = {},
                          // what scope property is currently updating
                          scopePropertyUpdating,
                          // the object added to the scope
                          componentScope,
                          frag;
  
                      // ## Scope
  
                      // Add scope prototype properties marked with an "@" to the `initialScopeData` object
                      can.each(this.constructor.attributeScopeMappings, function(val, prop) {
                          initalScopeData[prop] = el.getAttribute(can.hyphenate(val));
                      });
  
                      // Get the value in the scope for each attribute
                      // the hookup should probably happen after?
                      can.each(can.makeArray(el.attributes), function(node, index) {
                          var name = can.camelize(node.nodeName.toLowerCase()),
                              value = node.value;
  
  
  
                          // Ignore attributes already present in the ScopeMappings.
                          if (component.constructor.attributeScopeMappings[name] || ignoreAttributesRegExp.test(name) || viewCallbacks.attr(node.nodeName)) {
                              return;
                          }
                          // Only setup bindings if attribute looks like `foo="{bar}"`
                          if (value[0] === "{" && value[value.length - 1] === "}") {
                              value = value.substr(1, value.length - 2);
                          } else {
                              // Legacy template types will crossbind "foo=bar"
                              if (hookupOptions.templateType !== "legacy") {
                                  initalScopeData[name] = value;
                                  return;
                              }
                          }
                          // Cross-bind the value in the scope to this 
                          // component's scope
                          var computeData = hookupOptions.scope.computeData(value, {
                                  args: []
                              }),
                              compute = computeData.compute;
  
                          // bind on this, check it's value, if it has dependencies
                          var handler = function(ev, newVal) {
                              scopePropertyUpdating = name;
                              componentScope.attr(name, newVal);
                              scopePropertyUpdating = null;
                          };
  
                          // Compute only returned if bindable
                          compute.bind("change", handler);
  
                          // Set the value to be added to the scope
                          initalScopeData[name] = compute();
  
                          // We don't need to listen to the compute `change` if it doesn't have any dependencies
                          if (!compute.hasDependencies) {
                              compute.unbind("change", handler);
                          } else {
                              // Make sure we unbind (there's faster ways of doing this)
                              can.bind.call(el, "removed", function() {
                                  compute.unbind("change", handler);
                              });
                              // Setup the two-way binding
                              twoWayBindings[name] = computeData;
                          }
  
                      });
                      if (this.constructor.Map) {
                          // If `Map` property is set on the constructor use it to wrap the `initialScopeData`
                          componentScope = new this.constructor.Map(initalScopeData);
                      } else if (this.scope instanceof can.Map) {
                          // If `this.scope` is instance of `can.Map` assign it to the `componentScope`
                          componentScope = this.scope;
                      } else if (can.isFunction(this.scope)) {
                          // If `this.scope` is a function, call the function and 
                          var scopeResult = this.scope(initalScopeData, hookupOptions.scope, el);
  
                          if (scopeResult instanceof can.Map) {
                              // If the function returns a can.Map, use that as the scope
                              componentScope = scopeResult;
                          } else if (scopeResult.prototype instanceof can.Map) {
                              // If `scopeResult` is of a `can.Map` type, use it to wrap the `initialScopeData`
                              componentScope = new scopeResult(initalScopeData);
                          } else {
                              // Otherwise extend `can.Map` with the `scopeResult` and initialize it with the `initialScopeData`
                              componentScope = new(can.Map.extend(scopeResult))(initalScopeData);
                          }
  
                      }
  
                      // ## Two way bindings
  
                      // Object to hold the bind handlers so we can tear them down
                      var handlers = {};
                      // Setup reverse bindings
                      can.each(twoWayBindings, function(computeData, prop) {
                          handlers[prop] = function(ev, newVal) {
                              // Check that this property is not being changed because
                              // it's source value just changed
                              if (scopePropertyUpdating !== prop) {
                                  computeData.compute(newVal);
                              }
                          };
                          componentScope.bind(prop, handlers[prop]);
                      });
                      // Teardown reverse bindings when the element is removed
                      can.bind.call(el, "removed", function() {
                          can.each(handlers, function(handler, prop) {
                              componentScope.unbind(prop, handlers[prop]);
                          });
                      });
                      // Setup the attributes bindings
                      if (!can.isEmptyObject(this.constructor.attributeScopeMappings) || hookupOptions.templateType !== "legacy") {
                          // Bind on the `attributes` event and update the scope.
                          can.bind.call(el, "attributes", function(ev) {
                              // Convert attribute name from the `attribute-name` to the `attributeName` format.
                              var camelized = can.camelize(ev.attributeName);
                              if (!twoWayBindings[camelized]) {
                                  // If there is a mapping for this attribute, update the `componentScope` attribute
                                  componentScope.attr(camelized, el.getAttribute(ev.attributeName));
                              }
                          });
  
                      }
  
                      // Set `componentScope` to `this.scope` and set it to the element's `data` object as a `scope` property
                      this.scope = componentScope;
                      can.data(can.$(el), "scope", this.scope);
  
                      // Create a real Scope object out of the scope property
                      var renderedScope = hookupOptions.scope.add(this.scope),
                          options = {
                              helpers: {}
                          };
  
                      // ## Helpers
  
                      // Setup helpers to callback with `this` as the component
                      can.each(this.helpers || {}, function(val, prop) {
                          if (can.isFunction(val)) {
                              options.helpers[prop] = function() {
                                  return val.apply(componentScope, arguments);
                              };
                          }
                      });
  
                      // ## `events` control
  
                      // Create a control to listen to events
                      this._control = new this.constructor.Control(el, {
                              // Pass the scope to the control so we can listen to it's changes from the controller.
                              scope: this.scope
                          });
  
                      // ## Rendering
  
                      // If this component has a template (that we've already converted to a renderer)
                      if (this.constructor.renderer) {
                          // If `options.tags` doesn't exist set it to an empty object.
                          if (!options.tags) {
                              options.tags = {};
                          }
  
                          // We need be alerted to when a <content> element is rendered so we can put the original contents of the widget in its place
                          options.tags.content = function contentHookup(el, rendererOptions) {
                              // First check if there was content within the custom tag
                              // otherwise, render what was within <content>, the default code
                              var subtemplate = hookupOptions.subtemplate || rendererOptions.subtemplate;
  
                              if (subtemplate) {
  
                                  // `rendererOptions.options` is a scope of helpers where `<content>` was found, so
                                  // the right helpers should already be available.
                                  // However, `_tags.content` is going to point to this current content callback.  We need to 
                                  // remove that so it will walk up the chain
  
                                  delete options.tags.content;
  
                                  can.view.live.replace([el], subtemplate(
                                          // This is the context of where `<content>` was found
                                          // which will have the the component's context
                                          rendererOptions.scope,
  
                                          rendererOptions.options));
  
                                  // Restore the content tag so it could potentially be used again (as in lists)
                                  options.tags.content = contentHookup;
                              }
                          };
                          // Render the component's template
                          frag = this.constructor.renderer(renderedScope, hookupOptions.options.add(options));
                      } else {
                          // Otherwise render the contents between the 
                          if (hookupOptions.templateType === "legacy") {
                              frag = can.view.frag(hookupOptions.subtemplate ? hookupOptions.subtemplate(renderedScope, hookupOptions.options.add(options)) : "");
                          } else {
                              frag = hookupOptions.subtemplate ? hookupOptions.subtemplate(renderedScope, hookupOptions.options.add(options)) : document.createDocumentFragment();
                          }
  
                      }
                      // Append the resulting document fragment to the element
                      can.appendChild(el, frag);
                  }