|
@@ -0,0 +1,448 @@
|
|
|
+<?php
|
|
|
+/**
|
|
|
+ * Created by PhpStorm.
|
|
|
+ * User: loconox
|
|
|
+ * Date: 28/03/2017
|
|
|
+ * Time: 16:16
|
|
|
+ */
|
|
|
+
|
|
|
+namespace AppBundle\CSL;
|
|
|
+
|
|
|
+
|
|
|
+class Name extends Format
|
|
|
+{
|
|
|
+ private $name_parts = array();
|
|
|
+ private $attr_init = false;
|
|
|
+
|
|
|
+ function __construct(\DOMElement $dom_node, CiteProc $citeproc = null)
|
|
|
+ {
|
|
|
+
|
|
|
+ $tags = $dom_node->getElementsByTagName('name-part');
|
|
|
+ if ($tags) {
|
|
|
+ foreach ($tags as $tag) {
|
|
|
+ $name_part = $tag->getAttribute('name');
|
|
|
+ $tag->removeAttribute('name');
|
|
|
+ for ($i = 0; $i < $tag->attributes->length; $i++) {
|
|
|
+ $value = $tag->attributes->item($i)->value;
|
|
|
+ $name = str_replace(' ', '_', $tag->attributes->item($i)->name);
|
|
|
+ $this->name_parts[$name_part][$name] = $value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ parent::__construct($dom_node, $citeproc);
|
|
|
+ }
|
|
|
+
|
|
|
+ function init_formatting()
|
|
|
+ {
|
|
|
+ $this->no_op = array();
|
|
|
+ $this->format = array();
|
|
|
+ $this->base = $this->get_attributes();
|
|
|
+ $this->format['base'] = '';
|
|
|
+ $this->format['family'] = '';
|
|
|
+ $this->format['given'] = '';
|
|
|
+ $this->no_op['base'] = true;
|
|
|
+ $this->no_op['family'] = true;
|
|
|
+ $this->no_op['given'] = true;
|
|
|
+
|
|
|
+ if (isset($this->prefix)) {
|
|
|
+ $this->no_op['base'] = false;
|
|
|
+ }
|
|
|
+ if (isset($this->suffix)) {
|
|
|
+ $this->no_op['base'] = false;
|
|
|
+ }
|
|
|
+ $this->init_format($this->base);
|
|
|
+
|
|
|
+
|
|
|
+ if (!empty($this->name_parts)) {
|
|
|
+ foreach ($this->name_parts as $name => $formatting) {
|
|
|
+ $this->init_format($formatting, $name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function init_attrs($mode)
|
|
|
+ {
|
|
|
+ // $and = $this->get_attributes('and');
|
|
|
+ if (isset($this->citeproc)) {
|
|
|
+ $style_attrs = $this->citeproc->style->get_hier_attributes();
|
|
|
+ $mode_attrs = $this->citeproc->{$mode}->get_hier_attributes();
|
|
|
+ $this->attributes = array_merge($style_attrs, $mode_attrs, $this->attributes);
|
|
|
+ }
|
|
|
+ if (isset($this->and)) {
|
|
|
+ if ($this->and == 'text') {
|
|
|
+ $this->and = $this->citeproc->get_locale('term', 'and');
|
|
|
+ } elseif ($this->and == 'symbol') {
|
|
|
+ $this->and = '&';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!isset($this->delimiter)) {
|
|
|
+ $this->delimiter = $this->{'name-delimiter'};
|
|
|
+ }
|
|
|
+ if (!isset($this->alnum)) {
|
|
|
+ list(
|
|
|
+ $this->alnum, $this->alpha, $this->cntrl, $this->dash,
|
|
|
+ $this->digit, $this->graph, $this->lower, $this->print,
|
|
|
+ $this->punct, $this->space, $this->upper, $this->word,
|
|
|
+ $this->patternModifiers
|
|
|
+ ) = $this->get_regex_patterns();
|
|
|
+ }
|
|
|
+ $this->dpl = $this->{'delimiter-precedes-last'};
|
|
|
+ $this->sort_separator = isset($this->{'sort-separator'}) ? $this->{'sort-separator'} : ', ';
|
|
|
+
|
|
|
+ $this->delimiter = isset($this->{'name-delimiter'}) ? $this->{'name-delimiter'} : (isset($this->delimiter) ? $this->delimiter : ', ');
|
|
|
+
|
|
|
+ $this->form = isset($this->{'name-form'}) ? $this->{'name-form'} : (isset($this->form) ? $this->form : 'long');
|
|
|
+
|
|
|
+ $this->attr_init = $mode;
|
|
|
+ }
|
|
|
+
|
|
|
+ function init_format($attribs, $part = 'base')
|
|
|
+ {
|
|
|
+ if (!isset($this->{$part})) {
|
|
|
+ $this->{$part} = array();
|
|
|
+ }
|
|
|
+ if (isset($attribs['quotes']) && strtolower($attribs['quotes']) == 'true') {
|
|
|
+ $this->{$part}['open-quote'] = $this->citeproc->get_locale('term', 'open-quote');
|
|
|
+ $this->{$part}['close-quote'] = $this->citeproc->get_locale('term', 'close-quote');
|
|
|
+ $this->{$part}['open-inner-quote'] = $this->citeproc->get_locale('term', 'open-inner-quote');
|
|
|
+ $this->{$part}['close-inner-quote'] = $this->citeproc->get_locale('term', 'close-inner-quote');
|
|
|
+ $this->no_op[$part] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isset($attribs['prefix'])) {
|
|
|
+ $this->{$part}['prefix'] = $attribs['prefix'];
|
|
|
+ }
|
|
|
+ if (isset($attribs['suffix'])) {
|
|
|
+ $this->{$part}['suffix'] = $attribs['suffix'];
|
|
|
+ }
|
|
|
+
|
|
|
+ $this->format[$part] .= (isset($attribs['font-style'])) ? 'font-style: '.$attribs['font-style'].';' : '';
|
|
|
+ $this->format[$part] .= (isset($attribs['font-family'])) ? 'font-family: '.$attribs['font-family'].';' : '';
|
|
|
+ $this->format[$part] .= (isset($attribs['font-weight'])) ? 'font-weight: '.$attribs['font-weight'].';' : '';
|
|
|
+ $this->format[$part] .= (isset($attribs['font-variant'])) ? 'font-variant: '.$attribs['font-variant'].';' : '';
|
|
|
+ $this->format[$part] .= (isset($attribs['text-decoration'])) ? 'text-decoration: '.$attribs['text-decoration'].';' : '';
|
|
|
+ $this->format[$part] .= (isset($attribs['vertical-align'])) ? 'vertical-align: '.$attribs['vertical-align'].';' : '';
|
|
|
+
|
|
|
+ if (isset($attribs['text-case'])) {
|
|
|
+ $this->no_op[$part] = false;
|
|
|
+ $this->{$part}['text-case'] = $attribs['text-case'];
|
|
|
+ }
|
|
|
+ if (!empty($this->format[$part])) {
|
|
|
+ $this->no_op[$part] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function format($text, $part = 'base')
|
|
|
+ {
|
|
|
+
|
|
|
+ if (empty($text) || $this->no_op[$part]) {
|
|
|
+ return $text;
|
|
|
+ }
|
|
|
+ if (isset($this->{$part}['text-case'])) {
|
|
|
+ switch ($this->{$part}['text-case']) {
|
|
|
+ case 'uppercase':
|
|
|
+ $text = mb_strtoupper($text);
|
|
|
+ break;
|
|
|
+ case 'lowercase':
|
|
|
+ $text = mb_strtolower($text);
|
|
|
+ break;
|
|
|
+ case 'capitalize-all':
|
|
|
+ $text = mb_convert_case($text, MB_CASE_TITLE);
|
|
|
+ break;
|
|
|
+ case 'capitalize-first':
|
|
|
+ $chr1 = mb_strtoupper(mb_substr($text, 0, 1));
|
|
|
+ $text = $chr1.mb_substr($text, 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $open_quote = isset($this->{$part}['open-quote']) ? $this->{$part}['open-quote'] : '';
|
|
|
+ $close_quote = isset($this->{$part}['close-quote']) ? $this->{$part}['close-quote'] : '';
|
|
|
+ $prefix = isset($this->{$part}['prefix']) ? $this->{$part}['prefix'] : '';
|
|
|
+ $suffix = isset($this->{$part}['suffix']) ? $this->{$part}['suffix'] : '';
|
|
|
+ if ($text[(strlen($text) - 1)] == $suffix) {
|
|
|
+ unset($suffix);
|
|
|
+ }
|
|
|
+ if (!empty($this->format[$part])) {
|
|
|
+ $text = '<span style="'.$this->format[$part].'">'.$text.'</span>';
|
|
|
+ }
|
|
|
+
|
|
|
+ return $prefix.$open_quote.$text.$close_quote.$suffix;
|
|
|
+ }
|
|
|
+
|
|
|
+ function render($names, $mode = null)
|
|
|
+ {
|
|
|
+ $text = '';
|
|
|
+ $authors = array();
|
|
|
+ $count = 0;
|
|
|
+ $auth_count = 0;
|
|
|
+ $et_al_triggered = false;
|
|
|
+
|
|
|
+ if (!$this->attr_init || $this->attr_init != $mode) {
|
|
|
+ $this->init_attrs($mode);
|
|
|
+ }
|
|
|
+
|
|
|
+ $initialize_with = $this->{'initialize-with'};
|
|
|
+
|
|
|
+ foreach ($names as $rank => $name) {
|
|
|
+ $count++;
|
|
|
+ //$given = (!empty($name->firstname)) ? $name->firstname : '';
|
|
|
+ if (!empty($name->given) && isset($initialize_with)) {
|
|
|
+ $name->given = preg_replace(
|
|
|
+ "/([$this->upper])[$this->lower]+/$this->patternModifiers",
|
|
|
+ '\\1',
|
|
|
+ $name->given
|
|
|
+ );
|
|
|
+ $name->given = preg_replace(
|
|
|
+ "/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers",
|
|
|
+ "",
|
|
|
+ $name->given
|
|
|
+ );
|
|
|
+ if (isset($name->initials)) {
|
|
|
+ $name->initials = $name->given.$name->initials;
|
|
|
+ }
|
|
|
+ $name->initials = $name->given;
|
|
|
+ }
|
|
|
+ if (isset($name->initials)) {
|
|
|
+ // within initials, remove any dots:
|
|
|
+ $name->initials = preg_replace("/([$this->upper])\.+/$this->patternModifiers", "\\1", $name->initials);
|
|
|
+ // within initials, remove any spaces *between* initials:
|
|
|
+ $name->initials = preg_replace(
|
|
|
+ "/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers",
|
|
|
+ "",
|
|
|
+ $name->initials
|
|
|
+ );
|
|
|
+ if ($this->citeproc->style->{'initialize-with-hyphen'} == 'false') {
|
|
|
+ $name->initials = preg_replace("/-/", '', $name->initials);
|
|
|
+ }
|
|
|
+ // within initials, add a space after a hyphen, but only if ...
|
|
|
+ if (preg_match(
|
|
|
+ "/ $/",
|
|
|
+ $initialize_with
|
|
|
+ )) {// ... the delimiter that separates initials ends with a space
|
|
|
+ // $name->initials = preg_replace("/-(?=[$this->upper])/$this->patternModifiers", " -", $name->initials);
|
|
|
+ }
|
|
|
+ // then, separate initials with the specified delimiter:
|
|
|
+ $name->initials = preg_replace(
|
|
|
+ "/([$this->upper])(?=[^$this->lower]+|$)/$this->patternModifiers",
|
|
|
+ "\\1$initialize_with",
|
|
|
+ $name->initials
|
|
|
+ );
|
|
|
+
|
|
|
+ // $shortenInitials = (isset($options['numberOfInitialsToKeep'])) ? $options['numberOfInitialsToKeep'] : FALSE;
|
|
|
+ // if ($shortenInitials) $given = drupal_substr($given, 0, $shortenInitials);
|
|
|
+
|
|
|
+ if (isset($initialize_with)) {
|
|
|
+ $name->given = $name->initials;
|
|
|
+ } elseif (!empty($name->given)) {
|
|
|
+ $name->given = $name->given.' '.$name->initials;
|
|
|
+ } elseif (empty($name->given)) {
|
|
|
+ $name->given = $name->initials;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $ndp = (isset($name->{'non-dropping-particle'})) ? $name->{'non-dropping-particle'}.' ' : '';
|
|
|
+ $suffix = (isset($name->{'suffix'})) ? ' '.$name->{'suffix'} : '';
|
|
|
+
|
|
|
+ if (isset($name->given)) {
|
|
|
+ $given = $this->format($name->given, 'given');
|
|
|
+ } else {
|
|
|
+ $given = '';
|
|
|
+ }
|
|
|
+ if (isset($name->family)) {
|
|
|
+ $name->family = $this->format($name->family, 'family');
|
|
|
+ if ($this->form == 'short') {
|
|
|
+ $text = $ndp.$name->family;
|
|
|
+ } else {
|
|
|
+ switch ($this->{'name-as-sort-order'}) {
|
|
|
+ case 'first' && $rank == 0:
|
|
|
+ case 'all':
|
|
|
+ $text = $ndp.$name->family.$this->sort_separator.$given;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ $text = $given.' '.$ndp.$name->family.$suffix;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $authors[] = trim($this->format($text));
|
|
|
+ }
|
|
|
+ if (isset($this->{'et-al-min'}) && $count >= $this->{'et-al-min'}) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isset($this->{'et-al-min'}) &&
|
|
|
+ $count >= $this->{'et-al-min'} &&
|
|
|
+ isset($this->{'et-al-use-first'}) &&
|
|
|
+ $count >= $this->{'et-al-use-first'} &&
|
|
|
+ count($names) > $this->{'et-al-use-first'}
|
|
|
+ ) {
|
|
|
+ if ($this->{'et-al-use-first'} < $this->{'et-al-min'}) {
|
|
|
+ for ($i = $this->{'et-al-use-first'}; $i < $count; $i++) {
|
|
|
+ unset($authors[$i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($this->etal) {
|
|
|
+ $etal = $this->etal->render();
|
|
|
+ } else {
|
|
|
+ $etal = $this->citeproc->get_locale('term', 'et-al');
|
|
|
+ }
|
|
|
+ $et_al_triggered = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($authors) && !$et_al_triggered) {
|
|
|
+ $auth_count = count($authors);
|
|
|
+ if (isset($this->and) && $auth_count > 1) {
|
|
|
+ $authors[$auth_count - 1] = $this->and.' '.$authors[$auth_count - 1]; //stick an "and" in front of the last author if "and" is defined
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $text = implode($this->delimiter, $authors);
|
|
|
+
|
|
|
+ if (!empty($authors) && $et_al_triggered) {
|
|
|
+ switch ($this->{'delimiter-precedes-et-al'}) {
|
|
|
+ case 'never':
|
|
|
+ $text = $text." $etal";
|
|
|
+ break;
|
|
|
+ case 'always':
|
|
|
+ $text = $text."$this->delimiter$etal";
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ $text = count($authors) == 1 ? $text." $etal" : $text."$this->delimiter$etal";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($this->form == 'count') {
|
|
|
+ if (!$et_al_triggered) {
|
|
|
+ return (int)count($authors);
|
|
|
+ } else {
|
|
|
+ return (int)(count($authors) - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // strip out the last delimiter if not required
|
|
|
+ if (isset($this->and) && $auth_count > 1) {
|
|
|
+ $last_delim = strrpos($text, $this->delimiter.$this->and);
|
|
|
+ switch ($this->dpl) { //dpl == delimiter proceeds last
|
|
|
+ case 'always':
|
|
|
+ return $text;
|
|
|
+ break;
|
|
|
+ case 'never':
|
|
|
+ return substr_replace($text, ' ', $last_delim, strlen($this->delimiter));
|
|
|
+ break;
|
|
|
+ case 'contextual':
|
|
|
+ default:
|
|
|
+ if ($auth_count < 3) {
|
|
|
+ return substr_replace($text, ' ', $last_delim, strlen($this->delimiter));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $text;
|
|
|
+ }
|
|
|
+
|
|
|
+ function get_regex_patterns()
|
|
|
+ {
|
|
|
+ // Checks if PCRE is compiled with UTF-8 and Unicode support
|
|
|
+ if (!@preg_match('/\pL/u', 'a')) {
|
|
|
+ // probably a broken PCRE library
|
|
|
+ return $this->get_latin1_regex();
|
|
|
+ } else {
|
|
|
+ // Unicode safe filter for the value
|
|
|
+ return $this->get_utf8_regex();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function get_latin1_regex()
|
|
|
+ {
|
|
|
+ $alnum = "[:alnum:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
|
|
|
+ // Matches ISO-8859-1 letters:
|
|
|
+ $alpha = "[:alpha:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
|
|
|
+ // Matches ISO-8859-1 control characters:
|
|
|
+ $cntrl = "[:cntrl:]";
|
|
|
+ // Matches ISO-8859-1 dashes & hyphens:
|
|
|
+ $dash = "-–";
|
|
|
+ // Matches ISO-8859-1 digits:
|
|
|
+ $digit = "[\d]";
|
|
|
+ // Matches ISO-8859-1 printing characters (excluding space):
|
|
|
+ $graph = "[:graph:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
|
|
|
+ // Matches ISO-8859-1 lower case letters:
|
|
|
+ $lower = "[:lower:]äåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
|
|
|
+ // Matches ISO-8859-1 printing characters (including space):
|
|
|
+ $print = "[:print:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
|
|
|
+ // Matches ISO-8859-1 punctuation:
|
|
|
+ $punct = "[:punct:]";
|
|
|
+ // Matches ISO-8859-1 whitespace (separating characters with no visual representation):
|
|
|
+ $space = "[\s]";
|
|
|
+ // Matches ISO-8859-1 upper case letters:
|
|
|
+ $upper = "[:upper:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆ";
|
|
|
+ // Matches ISO-8859-1 "word" characters:
|
|
|
+ $word = "_[:alnum:]ÄÅÁÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÍÌÎÏÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
|
|
|
+ // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
|
|
|
+ // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
|
|
|
+ $patternModifiers = "";
|
|
|
+
|
|
|
+ return array(
|
|
|
+ $alnum,
|
|
|
+ $alpha,
|
|
|
+ $cntrl,
|
|
|
+ $dash,
|
|
|
+ $digit,
|
|
|
+ $graph,
|
|
|
+ $lower,
|
|
|
+ $print,
|
|
|
+ $punct,
|
|
|
+ $space,
|
|
|
+ $upper,
|
|
|
+ $word,
|
|
|
+ $patternModifiers
|
|
|
+ );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function get_utf8_regex()
|
|
|
+ {
|
|
|
+ // Matches Unicode letters & digits:
|
|
|
+ $alnum = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:alnum:]"
|
|
|
+ // Matches Unicode letters:
|
|
|
+ $alpha = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}"; // Unicode-aware equivalent of "[:alpha:]"
|
|
|
+ // Matches Unicode control codes & characters not in other categories:
|
|
|
+ $cntrl = "\p{C}"; // Unicode-aware equivalent of "[:cntrl:]"
|
|
|
+ // Matches Unicode dashes & hyphens:
|
|
|
+ $dash = "\p{Pd}";
|
|
|
+ // Matches Unicode digits:
|
|
|
+ $digit = "\p{Nd}"; // Unicode-aware equivalent of "[:digit:]"
|
|
|
+ // Matches Unicode printing characters (excluding space):
|
|
|
+ $graph = "^\p{C}\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:graph:]"
|
|
|
+ // Matches Unicode lower case letters:
|
|
|
+ $lower = "\p{Ll}\p{M}"; // Unicode-aware equivalent of "[:lower:]"
|
|
|
+ // Matches Unicode printing characters (including space):
|
|
|
+ $print = "\P{C}"; // same as "^\p{C}", Unicode-aware equivalent of "[:print:]"
|
|
|
+ // Matches Unicode punctuation (printing characters excluding letters & digits):
|
|
|
+ $punct = "\p{P}"; // Unicode-aware equivalent of "[:punct:]"
|
|
|
+ // Matches Unicode whitespace (separating characters with no visual representation):
|
|
|
+ $space = "\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:space:]"
|
|
|
+ // Matches Unicode upper case letters:
|
|
|
+ $upper = "\p{Lu}\p{Lt}"; // Unicode-aware equivalent of "[:upper:]"
|
|
|
+ // Matches Unicode "word" characters:
|
|
|
+ $word = "_\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:word:]" (or "[:alnum:]" plus "_")
|
|
|
+ // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
|
|
|
+ // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
|
|
|
+ $patternModifiers = "u"; // the "u" (PCRE_UTF8) pattern modifier causes PHP/PCRE to treat pattern strings as UTF-8
|
|
|
+
|
|
|
+ return array(
|
|
|
+ $alnum,
|
|
|
+ $alpha,
|
|
|
+ $cntrl,
|
|
|
+ $dash,
|
|
|
+ $digit,
|
|
|
+ $graph,
|
|
|
+ $lower,
|
|
|
+ $print,
|
|
|
+ $punct,
|
|
|
+ $space,
|
|
|
+ $upper,
|
|
|
+ $word,
|
|
|
+ $patternModifiers
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+}
|