当前位置: 首页>>代码示例>>Python>>正文


Python LogStream.logDebug方法代码示例

本文整理汇总了Python中LogStream.logDebug方法的典型用法代码示例。如果您正苦于以下问题:Python LogStream.logDebug方法的具体用法?Python LogStream.logDebug怎么用?Python LogStream.logDebug使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在LogStream的用法示例。


在下文中一共展示了LogStream.logDebug方法的10个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Python代码示例。

示例1: purgeOldSavedTables

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def purgeOldSavedTables(self, purgeTime):
        #purges old saved tables

        if self._activeTableFilename is None:
            raise Exception, "purgeOldSavedTables without filename"

        #calculate purge time
        purgeTime = time.time() - (purgeTime * 3600)

        #directory and files
        directory = os.path.join(os.path.dirname(self._activeTableFilename), "backup")
        baseN = os.path.basename(self._activeTableFilename)
        idx = baseN.find(".")
        if idx != -1:
            baseN = baseN[0:idx]
        files = glob.glob(directory + "/*" + baseN + "*.gz")

        #delete files older than purgeTime
        for f in files:
            try:
                modTime = os.stat(f)[stat.ST_MTIME] 
                if modTime < purgeTime:
                    os.remove(f)
                    LogStream.logDebug("Removing old file: ", f)
            except:
                LogStream.logProblem("Problem Removing old backup file: ", f,
                  LogStream.exc())
开发者ID:KeithLatteri,项目名称:awips2,代码行数:29,代码来源:VTECTableUtil.py

示例2: _getTextCaptureCategories

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
 def _getTextCaptureCategories(self):
     #gets the list of product categories that need their text captured.
     #if the list is empty, then all products are captured into the
     #active table and None is returned.
     cats = getattr(VTECPartners, "VTEC_CAPTURE_TEXT_CATEGORIES", [])
     if len(cats) == 0:
         return None
     LogStream.logDebug("Text Capture Categories: ", cats)
     return cats
开发者ID:KeithLatteri,项目名称:awips2,代码行数:11,代码来源:ActiveTable.py

示例3: decode

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def decode(self):
        #get pil and date-time group
        self._productPil, self._issueTime, linePos,\
          self._completeProductPil  = self._getPilAndDTG()
          
         # If this is a WCL - don't go any further. Run WCL procedure and exit.
        if self._productPil[0:3] == "WCL":
            endpoint = "WCLWatch"
            # build a Java object for the warning
            from com.raytheon.edex.plugin.gfe.wcl import WclInfo
            import JUtil
            lines = JUtil.pyValToJavaObj(self._lines)
            warning = WclInfo(long(self._issueTime * 1000),
                              self._completeProductPil, lines, self._notifyGFE)
            from com.raytheon.uf.edex.core import EDEXUtil
            EDEXUtil.getMessageProducer().sendAsync(endpoint, warning)
            LogStream.logEvent("%s forwarded to WCLWatch" % self._productPil)
            return []
       
        # Determine if this is a segmented product
        segmented = self._determineSegmented(linePos)
 
        # Get overview text
        if segmented == 1:
            self._overviewText, linePos = self._getOverviewText(linePos)      
        else:
            self._overviewText = ''
        LogStream.logDebug("OverviewText: ", self._overviewText)

        #find all UGCs, VTEC strings, and segment text
        ugcVTECList = self._getUGCAndVTECStrings(linePos)       
        
        self._polygon = self._getPolygon(linePos)
        self._storm = self._getStorm(linePos)

        #convert UGC strings into UGC list
        ugcVTECSegText = []
        segCount = 1
        for ugcString, vtecStrings, segText, cities in ugcVTECList:
            purgeTime = None
            self._checkForDTG(ugcString)
            if self._hasDTG:
                purgeTime = self._dtgFromDDHHMM(ugcString[-7:-1])
            else:
                purgeTime = self._getPurgeTimeFromVTEC(vtecStrings)            
            vtecList = self._expandVTEC(ugcString, vtecStrings, segCount,
              segText, cities, purgeTime)
            segCount = segCount + 1
            for r in vtecList:
                ugcVTECSegText.append(r)
        if len(ugcVTECSegText) == 0:
            LogStream.logVerbose("No VTEC Found in product")
            return

        return ugcVTECSegText
开发者ID:KeithLatteri,项目名称:awips2,代码行数:57,代码来源:WarningDecoder.py

示例4: _getOverviewText

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def _getOverviewText(self, startLine):
        #searches through the product from the startLine to the date-time 
        #group, then until the first UGC line.  Extracts out the text for 
        #the overview text (which is after the MND header.  Returns the 
        #overviewText.
        count = startLine
        ugcLine = None

        #search for the MND header date line
        while 1:
            dline_search = re.search(self._dlineRE, self._lines[count])
            count = count + 1
            if dline_search:
                break
            if count >= len(self._lines)-1:
                raise Exception, "No MND date line to start overview text"
        startOverviewLine = count  #next line after MND date line

        #search for the 1st UGC line 
        ugcRE = r'^[A-Z][A-Z][CZ][0-9][0-9][0-9].*'
        while 1:
            ugc_search = re.search(ugcRE, self._lines[count])
            if ugc_search:
                stopOverviewLine = count - 1
                break
            count = count + 1
            if count >= len(self._lines)-1:
                raise Exception, "No UGC line to end overview text"

        #now eliminate any blank lines between the start/stop overview line
        while startOverviewLine <= stopOverviewLine:
            if len(string.strip(self._lines[startOverviewLine])) != 0:
                break
            startOverviewLine = startOverviewLine + 1
        while startOverviewLine <= stopOverviewLine:
            if len(string.strip(self._lines[stopOverviewLine])) != 0:
                break
            stopOverviewLine = stopOverviewLine - 1

        LogStream.logDebug("start/stop overview: ", startOverviewLine, 
          stopOverviewLine)

        #put together the text
        if startOverviewLine <= stopOverviewLine:
            overviewLines = self._lines[startOverviewLine:stopOverviewLine+1]
            overviewText = string.join(overviewLines, '\n')
            return (overviewText, stopOverviewLine)
        else:
            return ("", startLine)
开发者ID:KeithLatteri,项目名称:awips2,代码行数:51,代码来源:WarningDecoder.py

示例5: preProcessTool

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def preProcessTool(self, varDict):
        # Called once at beginning of Tool
        # Cannot have WeatherElement or Grid arguments

        ########################################################################
        #  Get site ID
        try:
            siteID=self.mutableID().siteID()
        except:
            siteID=self._SITEID

        ########################################################################
        #  Get name of chosen model - and fix it up so we can use it later on.
        #  This will grab the latest version of the chosen model from the D2D
        #  netCDF files.
        self._model = "%s_D2D_%s" % (siteID, varDict["Model:"])

        ########################################################################
        #  Get chosen algorithm
        self._algorithm = varDict["Momentum algorithm:"]
        
        ########################################################################
        #  Get answer if we should use BL winds
        useBLwinds = varDict["Use BL Winds:"]
        
        ########################################################################
        #  Initialize a list of model levels
        self._modelCube = []

        ########################################################################
        #  Determine model levels available for each model
        if self._model.find( 'GFS80') != -1 or \
           self._model.find( 'GFS') != -1:
            self._modelCube = ["MB850", "MB700", "MB500", "MB400", "MB300"]
            self._blCube = []

        elif self._model.find( 'NAM12') != -1:
            self._modelCube = ["MB1000", "MB950", "MB900", "MB850", "MB800",
                               "MB750", "MB700", "MB650", "MB600", "MB550",
                               "MB500", "MB450", "MB400", "MB350"]
            self._blCube = ["BL030", "BL03060", "BL6090", "BL90120", "BL12015"]

        elif self._model.find( 'NAM40') != -1 or \
             self._model.find( 'NAM20') != -1:
            self._modelCube = ["MB975", "MB950", "MB925", "MB900", "MB875",
                               "MB850", "MB825", "MB800", "MB775", "MB750",
                               "MB725", "MB700", "MB675", "MB650", "MB625",
                               "MB600", "MB550", "MB500", "MB450", "MB400",
                               "MB350", "MB300"]
            self._blCube = ["BL030", "BL03060", "BL6090", "BL90120", "BL120150"]

        elif self._model.find( 'gfsLR') != -1:
            self._modelCube = ["MB1000", "MB850", "MB700", "MB500", "MB300"]
            self._blCube = []

        elif self._model.find( 'NGM80') != -1:
            self._modelCube = ["MB1000", "MB950", "MB850", "MB700", "MB500",
                               "MB400", "MB300"]
            self._blCube = ["FH1829", "FH2743", "FH3658"]

        elif self._model.find( 'RUC80') != -1:
            self._modelCube = ["MB1000", "MB950", "MB900", "MB850", "MB800",
                               "MB750", "MB700", "MB650", "MB600", "MB550",
                               "MB500", "MB450", "MB400", "MB350", "MB300"]
            self._blCube = ["BL030", "BL6090", "BL15018"]

        ########################################################################
        #  If we should not use the BL winds
        if useBLwinds is 'No':

            ####################################################################
            #  Reset the levels in the BL cube so we don't do anything
            self._blCube = []

        ########################################################################
        #  Determine height of all possible BL levels available for each model.
        #  If level is not at a fixed height AGL, use the hydrostatic equation.
        #  Assume the density of the air is 1 kg/m3 and gravity is 9.80 m/s^2.
        #  The height will be in m AGL at the center of the layer.  Remember
        #  there are 100 Pa per 1 mb.
        self._blHgt = {'BL030'   : (15.0 * 100.0/ 9.8),
                       'BL3060'  : (45.0 * 100.0 / 9.8),
                       'BL03060'  : (45.0 * 100.0 / 9.8),
                       'BL6090'  : (75.0 * 100.0 / 9.8),
                       'BL90120' : (105.0 * 100.0 / 9.8),
                       'BL12015' : (135.0 * 100.0 / 9.8),
                       'BL120150': (135.0 * 100.0 / 9.8),
                       'BL15018' : (165.0 * 100.0 / 9.8),
                       'FH1829'  : 1829.0,
                       'FH2743'  : 2743.0,
                       'FH3658'  : 3658.0
                      }
        
        LogStream.logDebug(toolName, ': preProcessTool complete.')
开发者ID:KeithLatteri,项目名称:awips2,代码行数:96,代码来源:WindGustFromAlgorithm.py

示例6: _getUGCAndVTECStrings

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def _getUGCAndVTECStrings(self, lineStart):
        #goes through the product, extracts UGC and VTEC strings and the
        #segment text, returns a list of (UGC keys, VTEC strings, segText).
        #Segment number is determined by order in the list.
        ugcList = []
        count = lineStart   #start on line following PIL
        while 1:
            #look for the first UGC line
            if re.search(r'^[A-Z][A-Z][CZ][0-9][0-9][0-9].*',
              self._lines[count]):
                LogStream.logDebug("First line of UGC found on line: ", count,
                  '[' + self._lines[count] + ']')
                
                #print "ugc found on line ", count

                #find the line with the terminating ugc (dtg), might be
                #the same one. Terminating line has -mmddhh
                #combine all of the UGC lines that are split across
                nxt = 0  #number of lines from the first UGC line
                ugc = "" #final UGC codes
                while count+nxt < len(self._lines):
                    if not re.search(r'.*[0-9][0-9][0-9][0-9][0-9][0-9]-',
                      self._lines[count+nxt]):
                        nxt = nxt + 1
                    else:
                        LogStream.logDebug("Last line of UGC found on line: ",
                          count+nxt, '[' + self._lines[count+nxt] + ']')
                        ugc = string.join(self._lines[count:count+nxt+1],
                          sep="")
                        break
                    
                    #after incrementing check if the next line is not a 
                    #continuation of the ugc because it is a vtec string
                    #print "checking for non-ugc"
                    #print self._lines[count+nxt]
                    if re.search(self._vtecRE, self._lines[count+nxt]):
                        LogStream.logDebug("Last line of UCG was previous line: ",
                                           count+nxt,
                                           '[' + self._lines[count+nxt-1] + ']')
                        nxt = nxt - 1
                        ugc = string.join(self._lines[count:count+nxt+1],sep="")
                        break
                
                if len(ugc) == 0:
                    s = "Did not find end of UGC line which started on " +\
                      " line " + `count`
                    LogStream.logProblem(s)
                    raise Exception, "Aborting due to bad UGC lines"


                #find the VTEC codes following the ugc line(s)
                nxt = nxt + 1  #go the 1st line after ugc
                vtectext = []
                while count+nxt < len(self._lines):
                    if re.search(self._vtecRE, self._lines[count+nxt]):
                        hvtec = None
                        if re.search(self._hVtecRE, self._lines[count+nxt+1]):
                            hvtec = self._lines[count+nxt+1]
                        vtectext.append((self._lines[count+nxt], hvtec))
                        LogStream.logDebug("VTEC found on line: ",
                          count+nxt, self._lines[count+nxt])
                    elif (re.search(self._badVtecRE, self._lines[count+nxt]) \
                      and not re.search(self._hVtecRE, self._lines[count+nxt])):
                        LogStream.logProblem("Bad VTEC line detected on line#",
                          count+nxt, '[' + self._lines[count+nxt] + ']',
                          'UGC=', ugc)
                        raise Exception,"Aborting due to bad VTEC line"
                    else:
                        break    #no more VTEC lines for this ugc
                    nxt = nxt + 1   #go to next line

                # for capturing the city names
                cityFirst = count+nxt
                cityLast = cityFirst - 1

                #capture the text from dtg to the $$ at the beginning of
                #the line.  Just in case there isn't a $$, we also look
                #for a new VTEC or UGC line, or the end of file.
                textFirst = count+nxt
                dtgFound = 0
                segmentText = ""
                while count+nxt < len(self._lines):

                    # Date-TimeGroup
                    if dtgFound == 0 and re.search(self._dlineRE, 
                      self._lines[count+nxt]):
                        cityLast = count+nxt-1
                        textFirst = count+nxt+2  #first text line
                        dtgFound = 1

                    # found the $$ line
                    elif re.search(self._endSegmentRE, self._lines[count+nxt]):
                        segmentText = self._prepSegmentText(\
                          self._lines[textFirst:count+nxt])
                        break

                    # found a UGC line, terminate the segment
                    elif re.search(r'^[A-Z][A-Z][CZ][0-9][0-9][0-9].*',
                      self._lines[count+nxt]):
                        segmentText = self._prepSegmentText(\
#.........这里部分代码省略.........
开发者ID:KeithLatteri,项目名称:awips2,代码行数:103,代码来源:WarningDecoder.py

示例7: squeeze

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def squeeze(self, table):

        if self.__debug:
            LogStream.logDebug("************** ORIGINAL TABLE *********************")
            LogStream.logDebug(self.__printActiveTable(table))

        # modify old UFN events (in case fcstrs didn't CAN them)
        table, modTable = self.__modifyOldUFNEvents(table)
        if self.__debug:
            LogStream.logDebug("************** MOD UFN TABLE *********************")
            for old, new in modTable:
                t = [old, new]
                LogStream.logDebug(self.__printActiveTable(t))
                LogStream.logDebug("    -----------")

        # remove the national center and short fused events 
        shortWFO, shortNC, purgeT = \
          self.__removeOldNationalAndShortFusedEvents(table)
        if self.__debug:
            LogStream.logDebug("************** SHORT WFO TABLE *********************")
            LogStream.logDebug(self.__printActiveTable(shortWFO))
            LogStream.logDebug("************** SHORT NATL CENTER TABLE *************")
            LogStream.logDebug(self.__printActiveTable(shortNC))
            LogStream.logDebug("************** INITIAL PURGE TABLE *************")
            LogStream.logDebug(self.__printActiveTable(purgeT))

        # separate out the shortWFO into dictionary structure
        dict = self.__separateTable(shortWFO)

        # purge old entries with LowerETNs that aren't in effect
        shorterT, purgeT2 = self.__purgeOldEntriesWithLowerETNs(dict)
        if self.__debug:
            LogStream.logDebug("************** TRIMMED WFO TABLE ******************")
            LogStream.logDebug(self.__printActiveTable(shorterT))
            LogStream.logDebug("************** ADDITIONAL PURGE TABLE *************")
            LogStream.logDebug(self.__printActiveTable(purgeT2))

        #add in any shortNC entries to final table
        for r in shortNC:
            shorterT.append(r)

        #add in the purged entries from before
        for r in purgeT2:
            purgeT.append(r)

        if self.__debug:
            LogStream.logDebug("************** FINAL TABLE ********************")
            LogStream.logDebug(self.__printActiveTable(shorterT))

        return shorterT, purgeT
开发者ID:KeithLatteri,项目名称:awips2,代码行数:52,代码来源:VTECTableSqueeze.py

示例8: __printTable

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def __printTable(self, d):
        oid = d.keys()
        oid.sort()
        for o in oid:
            LogStream.logDebug("----------------------")
            LogStream.logDebug("OFFICE: ", o)
            phensig = d[o].keys()
            phensig.sort()
        
            for ps in phensig:
                LogStream.logDebug("    phensig: ", ps)

                issuances = d[o][ps].keys()
                issuances.sort()

                for iy in issuances:
                    LogStream.logDebug("      issueyear: ", iy)
                    etns = d[o][ps][iy].keys()
                    etns.sort()
            
                    for etn in etns:
                        #
                        LogStream.logDebug("        etn: ", etn)
                        ids = d[o][ps][iy][etn].keys()
                        for id in ids:
                            LogStream.logDebug("            id: ", id)
                            self.__printActiveTable(d[o][ps][iy][etn][id])
开发者ID:KeithLatteri,项目名称:awips2,代码行数:29,代码来源:VTECTableSqueeze.py

示例9: __purgeOldEntriesWithLowerETNs

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def __purgeOldEntriesWithLowerETNs(self, d):
        saveRec = []
        purgeRec = []
        tropicalPhen=['TR','TY','HU']
        for o in d.keys():
            phensig = d[o].keys()
            for ps in phensig:
                issueYears = d[o][ps].keys()
                for iy in issueYears:
                    dd = d[o][ps][iy]
                    etns = dd.keys()

                    #get two maxetn for tropicalPhen (one for site created and the other
                    #for NHC created. The etn will be more than 100 for NHC hazards), 
                    #and the minimum id for this hazard
                    maxetn1 = max(etns)
                    maxetn2 = 0
                    if maxetn1 >= 1000: 
                       for my_etn in etns:
                          if my_etn > maxetn2 and my_etn < 1000:
                             maxetn2 = my_etn
                    else:
                       maxetn2 = maxetn1
                             
                    ids1 = dd[maxetn1]
                    minid1 = min(ids1)

                    ids2 = ids1
                    minid2 = minid1

                    if maxetn2 > 0 and maxetn2 != maxetn1:
                       ids2 = dd[maxetn2]
                       minid2 = min(ids2)

                    #determine what to keep and what to toss 
                    for etn in etns:
                        all_hourOld = True
                        all_cancelled = True
                        all_twoWeeksOld = True
                        ufn = None

                        for id in dd[etn].keys():
                            for rec in dd[etn][id]:
                                if ufn is None:
                                    ufn = rec.get('ufn', False)
                                hourOld = self.__ctime > rec['endTime'] + (1*3600)
                                twoWeeksOld = self.__ctime > rec['issueTime'] + (14*86400)
                                cancelled = rec['act'] in ['CAN','UPG','EXP']
                                all_hourOld &= hourOld
                                all_cancelled &= cancelled
                                all_twoWeeksOld &= twoWeeksOld

                        # keep records if the event:
                        # 1. is UFN, not cancelled, and not older then two weeks.
                        # 2. not UFN, and not ended in the last hour
                        # 3. cancelled, from this year, keep only records that are minid, and maxetn

                        if ufn and not all_cancelled and not all_twoWeeksOld: # 1
                            for id in dd[etn].keys():
                                for rec in dd[etn][id]:
                                    saveRec.append(rec)

                        elif not ufn and not all_hourOld: # 2
                            for id in dd[etn].keys():
                                for rec in dd[etn][id]:
                                    saveRec.append(rec)

                        elif iy == self.__thisYear and etn == maxetn1: # 3
                            for id in dd[etn].keys():
                                if (id == minid1):
                                    for rec in dd[etn][id]:
                                        saveRec.append(rec)
                                else:
                                    for rec in dd[etn][id]:
                                        LogStream.logDebug("******** WILL PURGE *******", rec['vtecstr'])
                                        purgeRec.append(rec)
                
                        elif (iy == self.__thisYear) and (etn == maxetn2): # 3
                            for id in dd[etn].keys():
                                if (id == minid2):
                                    for rec in dd[etn][id]:
                                        saveRec.append(rec)
                                else:
                                    for rec in dd[etn][id]:
                                        LogStream.logDebug("******** WILL PURGE *******", rec['vtecstr'])
                                        purgeRec.append(rec)
                
                        else:
                            for id in dd[etn].keys():
                                for rec in dd[etn][id]:
                                    LogStream.logDebug("******** WILL PURGE *******", rec['vtecstr'])
                                    purgeRec.append(rec)

        return saveRec, purgeRec
开发者ID:KeithLatteri,项目名称:awips2,代码行数:96,代码来源:VTECTableSqueeze.py

示例10: execute

# 需要导入模块: import LogStream [as 别名]
# 或者: from LogStream import logDebug [as 别名]
    def execute(self, editArea, timeRange, varDict):
        # get the hazard utilities
        self._hazUtils = HazardUtils.HazardUtils(self._dbss, None)

        self.setToolType("numeric")

        # any temporary grids?
        if self._hazUtils._tempWELoaded():
            self.statusBarMsg("Unload temporary hazard weather elements before running HazardRecovery.",
                              "S")
            return

        # get the active table
        site4ID = self.getSite4ID(self.getSiteID())
        allZones = self.editAreaList()
        activeTable = self.getActiveTable(site4ID, allZones)

        # define this to define the dialog
        variableList = [
            ("Your entire Hazards inventory will be replaced with the " + \
             "contents of the active table.","", "label"),
            ]
        
        # call this to pop the dialog
        title = "Hazard Recovery"
        processVarList = ProcessVariableList.ProcessVariableList(title, \
                         variableList, varDict, parent = None)
        status = processVarList.status()
        if status.lower() != "ok":
            print "status:",  status
            LogStream.logDebug("HazardRecovery: cancel")
            return         
        LogStream.logDebug("HazardRecovery: OK")
        
        # see if the Hazards WE is loaded in the GFE, if not abort the tool
        if not self._hazUtils._hazardsLoaded():
            self.statusBarMsg("Hazards Weather Element must be loaded in the GFE" + \
                              " before running HazardRecovery", "S")
            return

        # remove all of the current hazard grids
        self._hazUtils._removeAllHazardsGrids()
        self._hazUtils._unlockHazards()
        
        # any hazards at all?
        if len(activeTable) == 0:
            self.statusBarMsg("There are no hazards in the active table to recover. Hazard grids have been cleared.",
                              "S")
            # return

        
        keys = activeTable.keys()
        allzones = self.editAreaList()
        for key, start, end, action in keys:
            timeRange = self._hazUtils._makeTimeRange(start, end)
            zoneList = activeTable[(key, start, end, action)]
            filteredZoneList = []
            for z in zoneList:
                if z in allzones:
                    filteredZoneList.append(z)

            mask = self._hazUtils._makeMask(filteredZoneList)
            self._hazUtils._addHazard("Hazards", timeRange, key, mask)

            LogStream.logEvent(self._hazUtils._printTime(start),
              self._hazUtils._printTime(end), key, zoneList)



        return
开发者ID:KeithLatteri,项目名称:awips2,代码行数:72,代码来源:HazardRecovery.py


注:本文中的LogStream.logDebug方法示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。