/**
     * Takes the instant law object and turns it into HTML, with embedded links, anchors, etc.
     */
    function render()
    {
        /*
         * Get the dictionary terms for this chapter.
         */
        $dictionary = new Dictionary();
        $dictionary->structure_id = $this->structure_id;
        $dictionary->section_id = $this->section_id;
        $tmp = $dictionary->term_list();
        if ($tmp !== FALSE) {
            $terms = (array) $tmp;
            unset($tmp);
        }
        /*
         * If we've gotten a list of dictionary terms.
         */
        if ($terms !== FALSE && is_array($terms)) {
            /*
             * Arrange our terms from longest to shortest. This is to ensure that the most specific
             * terms are defined (e.g. "person of interest") rather than the broadest terms (e.g.
             * "person").
             */
            usort($terms, 'sort_by_length');
            /*
             * Store a list of the dictionary terms as an array, which is required for
             * preg_replace_callback, the function that we use to insert the definitions.
             */
            $term_pcres = array();
            foreach ($terms as $term) {
                /*
                 * Step through each character in this word.
                 */
                for ($i = 0; $i < strlen($term); $i++) {
                    /*
                     * If there are any uppercase characters, then make this PCRE string case
                     * sensitive.
                     */
                    if (ord($term[$i]) >= 65 && ord($term[$i]) <= 90) {
                        $term_pcres[] = '/\\b' . $term . '(s?)\\b(?![^<]*>)/';
                        $caps = TRUE;
                        break;
                    }
                }
                /*
                 * If we have determined that this term does not contain capitalized letters, then
                 * create a case-insensitive PCRE string.
                 */
                if (!isset($caps)) {
                    $term_pcres[] = '/\\b' . $term . '(s?)\\b(?![^<]*>)/i';
                }
                /*
                 * Unset our flag -- we don't want to have it set the next time through.
                 */
                if (isset($caps)) {
                    unset($caps);
                }
            }
        }
        /*
         * Instantiate our autolinker, which embeds links. If we've defined a state-custom
         * autolinker, use that one. Otherwise, use the built-in one. Be sure not to attempt to
         * autoload a file fitting our class-name schema, since this class, if it exists, would be
         * found within class.[State].inc.php.
         */
        if (class_exists('State_Autolinker', FALSE) === TRUE) {
            $autolinker = new State_Autolinker();
        }
        $autolinker = new Autolinker();
        /*
         * Iterate through every section to make some basic transformations.
         */
        foreach ($this->text as $section) {
            /*
             * Prevent lines from wrapping in the middle of a section identifier.
             */
            $section->text = str_replace('§ ', '§&nbsp;', $section->text);
            /*
             * Turn every code reference in every paragraph into a link.
             */
            $section->text = preg_replace_callback(SECTION_REGEX, array($autolinker, 'replace_sections'), $section->text);
            /*
             * Turn every pair of newlines into carriage returns.
             */
            $section->text = preg_replace('/\\R\\R/', '<br /><br />', $section->text);
            /*
             * Use our dictionary to embed dictionary terms in the form of span titles.
             */
            if (isset($term_pcres)) {
                $section->text = preg_replace_callback($term_pcres, array($autolinker, 'replace_terms'), $section->text);
            }
        }
        $html = '';
        /*
         * Iterate through each section of text to display it.
         */
        $i = 0;
        $num_paragraphs = count((array) $this->text);
        foreach ($this->text as $paragraph) {
            /*
             * Identify the prior and next sections, by storing their prefixes.
             */
            if ($i > 0) {
                $paragraph->prior_prefix = $this->text->{$i - 1}->entire_prefix;
            }
            if ($i + 1 < $num_paragraphs) {
                $paragraph->next_prefix = $this->text->{$i + 1}->entire_prefix;
            }
            /*
             * If this paragraph's prefix hierarchy is different than that of the prior prefix, then
             * indicate that this is a new section.
             */
            if (!isset($paragraph->prior_prefix) || $paragraph->entire_prefix != $paragraph->prior_prefix) {
                $html .= '
					<section';
                if (!empty($paragraph->prefix_anchor)) {
                    $html .= ' id="' . $paragraph->prefix_anchor . '"';
                }
                /*
                 * If this is a subsection, indent it.
                 */
                if ($paragraph->level > 1) {
                    $html .= ' class="indent-' . ($paragraph->level - 1) . '"';
                }
                $html .= '>';
            }
            /*
             * Start a paragraph of the appropriate type.
             */
            if ($paragraph->type == 'section') {
                $html .= '<p>';
            } elseif ($paragraph->type == 'table') {
                $html .= '<div class="tabular"><pre class="table">';
            }
            /*
             * If we've got a section prefix, and it's not the same as the last one, then display
             * it.
             */
            if (!empty($paragraph->prefix) && (!isset($paragraph->prior_prefix) || $paragraph->entire_prefix != $paragraph->prior_prefix)) {
                $html .= $paragraph->prefix;
                /*
                 * We could use a regular expression to determine if we need to append a period, but
                 * that would be slower.
                 */
                if (substr($paragraph->prefix, -1) != ')' && substr($paragraph->prefix, -1) != '.') {
                    $html .= '.';
                }
                $html .= ' ';
            }
            /*
             * Display this section of text. Purely structural sections lack text of their own (only
             * their child structures contain text), which is why this is conditional.
             */
            if (!empty($paragraph->text)) {
                $html .= $paragraph->text;
            }
            /*
             * If we've got a section prefix, append a paragraph link to the end of this section.
             */
            if (!empty($paragraph->prefix) && !defined('EXPORT_IN_PROGRESS')) {
                /*
                 * Assemble the permalink
                 */
                $permalink = $_SERVER['REQUEST_URI'] . '#' . $paragraph->prefix_anchor;
                $html .= ' <a id="paragraph-' . $paragraph->id . '" class="section-permalink" ' . 'href="' . $permalink . '"><i class="icon-link"></i></a>';
            }
            if ($paragraph->type == 'section') {
                $html .= '</p>';
            } elseif ($paragraph->type == 'table') {
                $html .= '</pre></div>';
            }
            /*
             * If our next prefix is different than the current prefix, than terminate this section.
             */
            if (!isset($paragraph->next_prefix) || $paragraph->entire_prefix != $paragraph->next_prefix || $i + 1 === $num_paragraphs) {
                $html .= '</section>';
            }
            $i++;
        }
        return $html;
    }
 function handle($args)
 {
     /*
      * If we have received neither a term nor a section, we can't do anything.
      */
     if (empty($args['term']) && empty($_GET['section'])) {
         json_error('Neither a dictionary term nor a section number have been provided.');
         die;
     }
     /*
      * Clean up the term.
      */
     $term = filter_var($args['term'], FILTER_SANITIZE_STRING);
     /*
      * If a section has been specified, then clean that up.
      */
     if (isset($_GET['section'])) {
         $section = filter_input(INPUT_GET, 'section', FILTER_SANITIZE_STRING);
     }
     $dict = new Dictionary();
     /*
      * Get the definitions for the requested term, if a term has been requested.
      */
     if (!empty($args['term'])) {
         if (isset($section)) {
             $dict->section_number = $section;
         }
         $dict->term = $term;
         $dictionary = $dict->define_term();
         /*
          * If, for whatever reason, this term is not found, return an error.
          */
         if ($dictionary === FALSE) {
             $response = array('definition' => 'Definition not available.');
         } else {
             /*
              * Uppercase the first letter of the first (quoted) word. We perform this twice because
              * some egal codes begin the definition with a quotation mark and some do not. (That is,
              * some write '"Whale" is a large sea-going mammal' and some write 'Whale is a large
              * sea-going mammal.")
              */
             if (preg_match('/[A-Za-z]/', $dictionary->definition[0]) === 1) {
                 $dictionary->definition[0] = strtoupper($dictionary->definition[0]);
             } elseif (preg_match('/[A-Za-z]/', $dictionary->definition[1]) === 1) {
                 $dictionary->definition[1] = strtoupper($dictionary->definition[1]);
             }
             /*
              * If the request contains a specific list of fields to be returned.
              */
             if (isset($_GET['fields'])) {
                 /*
                  * Turn that list into an array.
                  */
                 $returned_fields = explode(',', urldecode($_GET['fields']));
                 foreach ($returned_fields as &$field) {
                     $field = trim($field);
                 }
                 /*
                  * It's essential to unset $field at the conclusion of the prior loop.
                  */
                 unset($field);
                 foreach ($dictionary as &$term) {
                     /*
                      * Step through our response fields and eliminate those that aren't in the
                      * requested list.
                      */
                     foreach ($term as $field => &$value) {
                         if (in_array($field, $returned_fields) === FALSE) {
                             unset($term->{$field});
                         }
                     }
                 }
             }
             /*
              * If a section has been specified, then simplify this response by returning just a
              * single definition.
              */
             if (isset($section)) {
                 $dictionary = $dictionary->{0};
             }
             /*
              * Rename this variable to use the expected name.
              */
             $response = $dictionary;
         }
         // end else if term is found
     } elseif (!empty($_GET['section'])) {
         /*
          * Get the structural ID of the container for this section.
          */
         $law = new Law();
         $law->section_number = $section;
         $law->config = FALSE;
         $result = $law->get_law();
         if ($result == FALSE) {
             $response = array('terms' => 'Term list not available.');
         } else {
             /*
              * Now get the term list.
              */
             $dict->section_id = $law->section_id;
             $dict->structure_id = $law->structure_id;
             $response = $dict->term_list();
             if ($response == FALSE) {
                 $response = array('terms' => 'Term list not available.');
             }
         }
     }
     // end elseif (!empty($args['section']))
     $this->render($response, 'OK', $_REQUEST['callback']);
 }