コード例 #1
0
 def interactive_action(self, display_option=None):
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'), cmd='less -R')
     else:
         if display_option.display_text == Constants.CASE_GET_ATTACH:
             lh = LaunchHelper(ListAttachments)
             lh.run('%s' % self.case)
         elif display_option.display_text == Constants.CASE_ADD_ATTACH:
             lh = LaunchHelper(AddAttachment)
             lh.run('-c %s' % self.case)
         elif display_option.display_text == Constants.CASE_ADD_COMMENT:
             lh = LaunchHelper(AddComment)
             lh.run('-c %s' % self.case)
             # Check if we need to reload the case as adding comments may
             # result in new options for case view.
             comments = self.case_obj.get_comments()
             if comments is None or len(comments) == 0:
                 self.postinit()
                 self.opts_updated = True
         elif (display_option.display_text == Constants.CASE_RECOMMENDATIONS
               and common.is_interactive()):
             lh = LaunchHelper(GenericPrompt)
             lh.run('', display_option)
         elif (display_option.display_text == Constants.CASE_MODIFY
               and common.is_interactive()):
             lh = LaunchHelper(ModifyCase)
             lh.run('%s' % self.case)
         else:
             doc = self._sections[display_option]
             pydoc.pipepager(doc.encode("UTF-8", 'replace'), cmd='less -R')
コード例 #2
0
 def interactive_action(self, display_option=None):
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'),
                         cmd='less -R')
     else:
         if display_option.display_text == Constants.CASE_GET_ATTACH:
             lh = LaunchHelper(ListAttachments)
             lh.run('%s' % self.case)
         elif display_option.display_text == Constants.CASE_ADD_ATTACH:
             lh = LaunchHelper(AddAttachment)
             lh.run('-c %s' % self.case)
         elif display_option.display_text == Constants.CASE_ADD_COMMENT:
             lh = LaunchHelper(AddComment)
             lh.run('-c %s' % self.case)
             # Check if we need to reload the case as adding comments may
             # result in new options for case view.
             comments = self.case_obj.get_comments()
             if comments is None or len(comments) == 0:
                 self.postinit()
                 self.opts_updated = True
         elif (display_option.display_text == Constants.CASE_RECOMMENDATIONS
               and common.is_interactive()):
             lh = LaunchHelper(GenericPrompt)
             lh.run('', display_option)
         elif (display_option.display_text == Constants.CASE_MODIFY
               and common.is_interactive()):
             lh = LaunchHelper(ModifyCase)
             lh.run('%s' % self.case)
         else:
             doc = self._sections[display_option]
             pydoc.pipepager(doc.encode("UTF-8", 'replace'), cmd='less -R')
コード例 #3
0
ファイル: search.py プロジェクト: karmab/redhat-support-tool
 def interactive_action(self, display_option=None):
     solution_id = None
     try:
         solution_id = display_option.stored_obj
         lh = LaunchHelper(Kb)
         lh.run(solution_id)
     except:
         raise Exception()
コード例 #4
0
 def interactive_action(self, display_option=None):
     solution_id = None
     try:
         solution_id = display_option.stored_obj
         lh = LaunchHelper(Kb)
         lh.run(solution_id)
     except:
         raise Exception()
コード例 #5
0
 def interactive_action(self, display_option=None):
     try:
         dopt_metadata = display_option.stored_obj
         lh = LaunchHelper(self.metadata['lhplugin'])
         if dopt_metadata['pt_obj']:
             display_option.stored_obj = dopt_metadata['pt_obj']
             lh.run(dopt_metadata['pt_str'], display_option)
         else:
             lh.run(dopt_metadata['pt_str'])
     except:
         raise
コード例 #6
0
 def interactive_action(self, display_option=None):
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'),
                         cmd='less -R')
     else:
         sol_id = display_option.stored_obj
         lh = LaunchHelper(Kb)
         lh.run(sol_id)
コード例 #7
0
 def interactive_action(self, display_option=None):
     '''
     This gets invoked when running in interactive mode
     Basically just a hook to get your sub command (symptom) invoked
     '''
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'), cmd='less -R')
     else:
         lh = LaunchHelper(Symptom)
         lh.run(None, display_option)
コード例 #8
0
 def interactive_action(self, display_option=None):
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'),
                         cmd='less -R')
     # Used by GetCase
     else:
         uuid = None
         uuid = display_option.stored_obj
         lh = LaunchHelper(GetAttachment)
         lh.run('-c %s -u %s' % (self.case, uuid))
コード例 #9
0
ファイル: analyze.py プロジェクト: karmab/redhat-support-tool
 def interactive_action(self, display_option=None):
     '''
     This gets invoked when running in interactive mode
     Basically just a hook to get your sub command (symptom) invoked
     '''
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'),
                         cmd='less -R')
     else:
         lh = LaunchHelper(Symptom)
         lh.run(None, display_option)
コード例 #10
0
 def interactive_action(self, display_option=None):
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'), cmd='less -R')
     else:
         val = None
         try:
             val = display_option.stored_obj
             lh = LaunchHelper(GetCase)
             lh.run(val)
         except:
             raise Exception()
コード例 #11
0
 def interactive_action(self, display_option=None):
     if display_option.display_text == self.ALL:
         doc = u''
         for opt in self._submenu_opts:
             if opt.display_text != self.ALL:
                 doc += self._sections[opt]
         pydoc.pipepager(doc.encode("UTF-8", 'replace'),
                         cmd='less -R')
     else:
         val = None
         try:
             val = display_option.stored_obj
             lh = LaunchHelper(GetCase)
             lh.run(val)
         except:
             raise Exception()
コード例 #12
0
    def _opencase(self, display_option=None):
        lh = LaunchHelper(OpenCase)
        try:
            # Remove nonprintable characters from the
            # crash output.  Argh!!!!
            filtered_string = filter(lambda x: x in string.printable,
                                     display_option.stored_obj)
            filtered_string = str(filtered_string).replace('"', ' ')
            filtered_string = str(filtered_string).replace("'", ' ')
            msg = None

            # If the filtered_string is too long (comments can only be
            # ~30k when formatting is applied, plus 20k is a large
            # chunk of text) attach it instead.
            if len(filtered_string) > 20000:
                try:
                    # Because we can't rename on the fly attachments,
                    # this filename is going to look 'odd'.
                    fd, temppath = tempfile.mkstemp(prefix="vmcoreinfo-",
                                                    suffix="-rhst")
                    attachment = os.fdopen(fd, "w")
                    attachment.write(filtered_string)
                    attachment.close()
                    lh.run('--attachment=%s' % (temppath))
                    os.remove(temppath)
                except:
                    print _('Unable to upload output to Red Hat'
                            ' Customer Portal, reverting to displaying'
                            ' output to console.')
            else:
                msg = '%s\nThe following comment was added by ' \
                      'Red Hat Support Tool\nVersion: %s\n' \
                      '%s\n\n%s' % \
                      (str(self.ruler * Constants.MAX_RULE),
                       apihelper.USER_AGENT,
                       str(self.ruler * Constants.MAX_RULE),
                       filtered_string)
                lh.run('-d \'%s\'' % msg)

        except Exception, e:
            msg = _('ERROR: %s') % e
            print msg
            logger.log(logging.ERROR, msg)
コード例 #13
0
ファイル: symptom.py プロジェクト: karmab/redhat-support-tool
    def _opencase(self, display_option=None):
        lh = LaunchHelper(OpenCase)
        try:
            # Remove nonprintable characters from the
            # crash output.  Argh!!!!
            filtered_string = filter(lambda x: x in string.printable,
                                     display_option.stored_obj)
            msg = None

            # If the filtered_string is too long (comments can only be
            # ~30k when formatting is applied, plus 20k is a large
            # chunk of text) attach it instead.
            if len(filtered_string) > 20000:
                try:
                    # Because we can't rename on the fly attachments,
                    # this filename is going to look 'odd'.
                    fd, temppath = tempfile.mkstemp(
                                                prefix="symptom-",
                                                suffix="-rhst")
                    attachment = os.fdopen(fd, "w")
                    attachment.write(filtered_string)
                    attachment.close()
                    lh.run('--attachment=%s' % (temppath))
                    os.remove(temppath)
                except:
                    print _('Unable to upload output to Red Hat'
                            ' Customer Portal, reverting to displaying'
                            ' output to console.')
            else:
                msg = '%s\nThe following comment was added by ' \
                      'Red Hat Support Tool\nVersion: %s\n' \
                      '%s\n\n%s' % \
                      (str(self.ruler * Constants.MAX_RULE),
                       apihelper.USER_AGENT,
                       str(self.ruler * Constants.MAX_RULE),
                       filtered_string)
                lh.run('-d \'%s\'' % msg)

        except Exception, e:
            msg = _('ERROR: %s') % e
            print msg
            logger.log(logging.ERROR, msg)
コード例 #14
0
 def _find_debug_symbols(self):
     '''
     At this point self.vmcore had better be non-null.  This
     method will call vmcorehelper's get_debug_symbols which scans
     the designated debug symbols directory looking for debug symbols
     which match the given core file.  If symbols are found, the
     VMCore object will be passed a VMLinux object.
     '''
     kernelext_dir = confighelper.get_config_helper().get(
         option='kern_debug_dir')
     vmlinux = vmcorehelper.get_debug_symbols(
         kernelext_dir, self.vmcore.getKernelVersion())
     if vmlinux:
         self.vmcore.setDebugSymbols(vmlinux)
     else:
         print _('WARNING: Debug symbols for %s were not found.') % \
                 self._args[0]
         line = raw_input(_('Would you like to install kernel-debuginfo-%s '
                 'from available debug repositories (y/n)? ') % \
                 self.vmcore.getKernelVersion())
         if str(line).strip().lower() == 'y':
             print _('Installing kernel-debuginfo-%s') % \
                 self.vmcore.getKernelVersion()
             lh = LaunchHelper(GetKernelDebugPackages)
             lh.run(self.vmcore.getKernelVersion(), pt_exception=True)
             vmlinux = vmcorehelper.get_debug_symbols(
                 kernelext_dir, self.vmcore.getKernelVersion())
             if vmlinux:
                 self.vmcore.setDebugSymbols(vmlinux)
             else:
                 raise Exception(
                     _('Installation of debug images failed, '
                       'cannot proceed with debug session'))
         else:
             raise Exception('User elected not to install debug '
                             'packages for kernel-debuginfo-%s' % \
                             self.vmcore.getKernelVersion())
コード例 #15
0
 def interactive_action(self, display_option=None):
     if display_option:
         lh = LaunchHelper(GetKernelDebugPackages)
         lh.run('', display_option)
     else:
         raise Exception()
コード例 #16
0
ファイル: symptom.py プロジェクト: karmab/redhat-support-tool
 def _send_to_shadowman(self, display_option=None):
     lh = LaunchHelper(Diagnose)
     lh.run('', display_option)
コード例 #17
0
    def non_interactive_action(self):
        api = None
        try:
            api = apihelper.get_api()

            case = api.im.makeCase()
            case.summary = self._options['summary']
            case.product = self._options['product']
            case.version = self._options['version']
            case.description = self._options['description']
            case.severity = self._options['severity']
            if self._options['casegroup']:
                case.folderNumber = self._options['casegroupnumber']

            if common.is_interactive():
                line = raw_input(_('Would see if there is a solution to this '
                            'problem before opening a support case? (y/N) '))
                line = str(line).strip().lower()
                if line == 'y':
                    recommendations = api.problems.diagnoseCase(case)
                    recprompt, recdoc = \
                        recommendationprompter.generate_metadata(
                                                            recommendations)
                    lh = LaunchHelper(GenericPrompt)
                    lh.run('', recprompt, prompt=_(\
                           'Selection (q returns to case creation menu): '))
                    line = raw_input(\
                                _('Would you still like to open the support'
                                  ' case? (Y/n) '))
                    if line.lower() == 'n':
                        print _('Thank you for using Red Hat Access')
                        return

            cs = api.cases.add(case)
            if cs.get_caseNumber() is None:
                msg = _("ERROR: There was a problem creating your case.")
                print msg
                raise Exception(msg)
            self._caseNumber = cs.get_caseNumber()
            print '%s%s%s' % (Constants.BOLD,
                                      str('-' * Constants.MAX_RULE),
                                      Constants.END)
            msg = _("Support case %s has successfully been opened.\n") % \
                self._caseNumber
            print msg
            logger.log(logging.INFO, msg)

            # Attach a file
            if self._options['attachment']:
                lh = LaunchHelper(AddAttachment)
                lh.run('-c %s -d \'[RHST] File %s \' %s' % (
                                self._caseNumber,
                                os.path.basename(self._options['attachment']),
                                self._options['attachment']))
            elif (os.geteuid() == 0):
                sys.stdout.write(_(
    'Would you like Red Hat Support Tool to automatically generate and\n'
    'attach a SoS report to %s now? (y/N) ') % (self._caseNumber))
                line = raw_input()

                line = str(line).strip()
                if line == 'y':
                    # retval = os.system('sosreport')
                    p = sub.Popen(['sosreport', '--batch'],
                                  stdout=sub.PIPE, stderr=sub.STDOUT)
                    output = p.communicate()[0].split('\n')
                    for out in output:
                        if '.tar.' in out:
                            path = str(out).strip()
                            lh = LaunchHelper(AddAttachment)
                            lh.run('-c %s %s' % (self._caseNumber, path))
                            break
            else:
                print _(
   'Please attach a SoS report to support case %s. Create a SoS report as\n'
   'the root user and execute the following command to attach the SoS report\n'
   'directly to the case:\n'
   ' redhat-support-tool addattachment -c %s <path to sosreport>\n') % \
    (self._caseNumber, self._caseNumber)

            if not self._options['attachment']:
                line = raw_input(_('Would you like to attach a file to %s '
                                   'at this time? (y/N) ') % self._caseNumber)
                line = str(line).strip()
                if line == 'y':
                    lh = LaunchHelper(AddAttachment)
                    lh.run('-c %s' % (self._caseNumber))
        except EmptyValueError, eve:
            msg = _('ERROR: %s') % str(eve)
            print msg
            logger.log(logging.WARNING, msg)
            raise
コード例 #18
0
    def non_interactive_action(self):
        api = None
        updatemsg = None
        if self.use_ftp:
            uploadloc = libconfig.ftp_host
        else: 
            uploadloc = "the case"
        caseNumber = self._options['casenumber']
        uploadBaseName = os.path.basename(self.upload_file)
        try:
            try:
                api = apihelper.get_api()

                print _("Uploading %s to %s ..." % (uploadBaseName,
                                                    uploadloc)),
                sys.stdout.flush()
                if self.split_attachment:
                    chunk = {'num': 0, 'names': [], 'size': self._options.get(
                             'splitsize', self.max_split_size)}
                    retVal = api.attachments.add(
                                    caseNumber=caseNumber,
                                    public=self._options['public'],
                                    fileName=self.upload_file,
                                    fileChunk=chunk,
                                    description=self._options['description'],
                                    useFtp=self.use_ftp)
                    if retVal:
                        print _("completed successfully.")
                        updatemsg = _('[RHST] The following split files were '
                                      'uploaded to %s:\n' % uploadloc)
                        for chunk_name in chunk['names']:
                            updatemsg += _('\n    %s' % chunk_name)

                else:
                    retVal = api.attachments.add(
                                    caseNumber=caseNumber,
                                    public=self._options['public'],
                                    fileName=self.upload_file,
                                    description=self._options['description'],
                                    useFtp=self.use_ftp)
                    if retVal:
                        print _("completed successfully.")
                        if self.use_ftp:
                            updatemsg = _('[RHST] The following attachment was'
                                          ' uploaded to %s:\n\n    %s-%s' %
                                          (libconfig.ftp_host, caseNumber,
                                           uploadBaseName))

                if retVal is None:
                    raise Exception()

                if updatemsg:
                    lh = LaunchHelper(AddComment)
                    comment_displayopt = ObjectDisplayOption(None, None,
                                                             [updatemsg])
                    lh.run('-c %s' % caseNumber, comment_displayopt)

            except EmptyValueError, eve:
                msg = _("ERROR: %s") % str(eve)
                print _("failed.\n" + msg)
                logger.error(msg)
                raise
            except RequestError, re:
                msg = _("ERROR: Unable to connect to support services API.  "
                        "Reason: %s    " % re.reason)
                print _("failed.\n" + msg)
                logger.error(msg)
                raise
コード例 #19
0
    def non_interactive_action(self):
        api = None
        updatemsg = None
        if self.use_ftp:
            uploadloc = libconfig.ftp_host
        else:
            uploadloc = "the case"
        caseNumber = self._options['casenumber']
        uploadBaseName = os.path.basename(self.upload_file)
        try:
            try:
                api = apihelper.get_api()

                print _("Uploading %s to %s ..." %
                        (uploadBaseName, uploadloc)),
                sys.stdout.flush()
                if self.split_attachment:
                    chunk = {
                        'num': 0,
                        'names': [],
                        'size': self._options.get('splitsize',
                                                  self.max_split_size)
                    }
                    retVal = api.attachments.add(
                        caseNumber=caseNumber,
                        public=self._options['public'],
                        fileName=self.upload_file,
                        fileChunk=chunk,
                        description=self._options['description'],
                        useFtp=self.use_ftp)
                    if retVal:
                        print _("completed successfully.")
                        updatemsg = _('[RHST] The following split files were '
                                      'uploaded to %s:\n' % uploadloc)
                        for chunk_name in chunk['names']:
                            updatemsg += _('\n    %s' % chunk_name)

                else:
                    retVal = api.attachments.add(
                        caseNumber=caseNumber,
                        public=self._options['public'],
                        fileName=self.upload_file,
                        description=self._options['description'],
                        useFtp=self.use_ftp)
                    if retVal:
                        print _("completed successfully.")
                        if self.use_ftp:
                            updatemsg = _('[RHST] The following attachment was'
                                          ' uploaded to %s:\n\n    %s-%s' %
                                          (libconfig.ftp_host, caseNumber,
                                           uploadBaseName))

                if retVal is None:
                    raise Exception()

                if updatemsg:
                    lh = LaunchHelper(AddComment)
                    comment_displayopt = ObjectDisplayOption(
                        None, None, [updatemsg])
                    lh.run('-c %s' % caseNumber, comment_displayopt)

            except EmptyValueError, eve:
                msg = _("ERROR: %s") % str(eve)
                print _("failed.\n" + msg)
                logger.error(msg)
                raise
            except RequestError, re:
                msg = _("ERROR: Unable to connect to support services API.  "
                        "Reason: %s    " % re.reason)
                print _("failed.\n" + msg)
                logger.error(msg)
                raise
コード例 #20
0
 def _send_to_shadowman(self, display_option=None):
     lh = LaunchHelper(Diagnose)
     lh.run('', display_option)
コード例 #21
0
 def interactive_action(self, display_option=None):
     if display_option:
         lh = LaunchHelper(GetKernelDebugPackages)
         lh.run('', display_option)
     else:
         raise Exception()
コード例 #22
0
    def non_interactive_action(self):
        api = None
        try:
            api = apihelper.get_api()

            case = api.im.makeCase()
            case.summary = self._options['summary']
            case.product = self._options['product']
            case.version = self._options['version']
            case.description = self._options['description']
            case.severity = self._options['severity']
            if self._options['casegroup']:
                case.folderNumber = self._options['casegroupnumber']

            if common.is_interactive():
                line = raw_input(
                    _('Would see if there is a solution to this '
                      'problem before opening a support case? (y/N) '))
                line = str(line).strip().lower()
                if line == 'y':
                    recommendations = api.problems.diagnoseCase(case)
                    recprompt, recdoc = \
                        recommendationprompter.generate_metadata(
                                                            recommendations)
                    lh = LaunchHelper(GenericPrompt)
                    lh.run('', recprompt, prompt=_(\
                           'Selection (q returns to case creation menu): '))
                    line = raw_input(\
                                _('Would you still like to open the support'
                                  ' case? (Y/n) '))
                    if line.lower() == 'n':
                        print _('Thank you for using Red Hat Access')
                        return

            cs = api.cases.add(case)
            if cs.get_caseNumber() is None:
                msg = _("ERROR: There was a problem creating your case.")
                print msg
                raise Exception(msg)
            self._caseNumber = cs.get_caseNumber()
            print '%s%s%s' % (Constants.BOLD, str(
                '-' * Constants.MAX_RULE), Constants.END)
            msg = _("Support case %s has successfully been opened.\n") % \
                self._caseNumber
            print msg
            logger.log(logging.INFO, msg)

            # Attach a file
            if self._options['attachment']:
                lh = LaunchHelper(AddAttachment)
                lh.run('-c %s -d \'[RHST] File %s \' %s' %
                       (self._caseNumber,
                        os.path.basename(self._options['attachment']),
                        self._options['attachment']))
            elif (os.geteuid() == 0):
                sys.stdout.write(
                    _('Would you like Red Hat Support Tool to automatically generate and\n'
                      'attach a SoS report to %s now? (y/N) ') %
                    (self._caseNumber))
                line = raw_input()

                line = str(line).strip()
                if line == 'y':
                    # retval = os.system('sosreport')
                    p = sub.Popen(['sosreport', '--batch'],
                                  stdout=sub.PIPE,
                                  stderr=sub.STDOUT)
                    output = p.communicate()[0].split('\n')
                    for out in output:
                        if '.tar.' in out:
                            path = str(out).strip()
                            lh = LaunchHelper(AddAttachment)
                            lh.run('-c %s %s' % (self._caseNumber, path))
                            break
            else:
                print _(
                'Please attach a SoS report to support case %s. Create a SoS report as\n'
                'the root user and execute the following command to attach the SoS report\n'
                'directly to the case:\n'
                ' redhat-support-tool addattachment -c %s <path to sosreport>\n') % \
    (self._caseNumber, self._caseNumber)

            if not self._options['attachment']:
                line = raw_input(
                    _('Would you like to attach a file to %s '
                      'at this time? (y/N) ') % self._caseNumber)
                line = str(line).strip()
                if line == 'y':
                    lh = LaunchHelper(AddAttachment)
                    lh.run('-c %s' % (self._caseNumber))
コード例 #23
0
                    # If the filtered_string is too long (comments can only be
                    # ~30k when formatting is applied, plus 20k is a large
                    # chunk of text) attach it instead.
                    if len(filtered_string) > 20000:
                        try:
                            # Because we can't rename on the fly attachments,
                            # this filename is going to look 'odd'.
                            fd, temppath = tempfile.mkstemp(
                                prefix="vmcoreinfo-", suffix="-rhst")
                            attachment = os.fdopen(fd, "w")
                            attachment.write(filtered_string)
                            attachment.close()
                            lh = LaunchHelper(AddAttachment)
                            lh.run('-c %s --description="%s" %s' %
                                   (self._options['casenumber'],
                                    opt.display_text.encode(
                                        "UTF-8", 'replace'), temppath))

                            os.remove(temppath)
                            msg = 'The attachment %s was uploaded by Red Hat' \
                                  ' Support Tool from the VMCore %s' % \
                                  (os.path.basename(temppath),
                                   self.vmcore.coreFilename)
                        except:
                            print _('Unable to upload output to Red Hat'
                                    ' Customer Portal, reverting to displaying'
                                    ' output to console.')
                    else:
                        msg = '%s\nThe following comment was added by ' \
                              'Red Hat Support Tool\nVersion: %s\n' \
                              '%s\n\n%s' % \