Thanks Thanks:  16
Seite 6 von 8 ErsteErste ... 45678 LetzteLetzte
Ergebnis 51 bis 60 von 78
  1. #51
    Avatar von betacentauri
    Registriert seit
    15.06.2013
    Beiträge
    1.799
    Total Downloaded
    1,32 MB
    Total Downloaded
    1,32 MB
    ReceiverDankeAktivitäten
    Box 1:
    ET-9200
     
     
    Box 2:
    ET-10000
     
     
    Box 3:
    ET-8500
     
     
    Box 4:
    ET-8000
     
     
    Box 5:
    Gigablue Quad+
     
     
    Das klingt sehr nach unserem Problem:
    #8871 (twisted.web cannot detect client termination on OS-X)
    – Twisted


    Steht zwar, dass das Linux nicht betrifft, aber vielleicht liegt es auch an der Architektur. Leider noch kein Fix.

    Edit: Und das würde das bestätigen was Arn354 schrieb. Mit altem Twisted ging es und dem neuen nicht mehr.
    ET-10000, ET-9200, ET-8000, Gigablue Quad+

    •   Alt Advertising

       

  2. #52
    Avatar von SpaceRat
    Registriert seit
    13.08.2013
    Ort
    Midgard
    Beiträge
    2.725
    Total Downloaded
    745,74 MB
    Total Downloaded
    745,74 MB
    ReceiverDankeAktivitäten
    Box 1:
    Vu+ Duo² 4x DVB-S2 OpenATV 6.1
     
     
    Box 2:
    AX QuadBox 2xDVB-S2 OpenATV 6.1
     
     
    Box 3:
    2x Vu+ Solo² OpenATV 6.1
     
     
    Box 4:
    Topfield TF7700 HDPVR HDMU
     
     
    Box 5:
    DVBViewer
     
     
    Zitat Zitat von betacentauri Beitrag anzeigen
    Edit: Und das würde das bestätigen was Arn354 schrieb. Mit altem Twisted ging es und dem neuen nicht mehr.
    Derselbe Fehler wurde schon am 26.03.2014 in HDMU beobachtet, also jetzt hört endlich auf von wegen alter Twisted.

    Schau doch mal in
    stream.py

    Da sehe ich:
    request.notifyFinish().addCallback(self.close, None)
    request.notifyFinish().addErrback(self.close, None)

    Also nur self.close, was ja anscheinend nicht reicht.

    Kann man aus der Erkenntnis plus
    reviewed by: xmartinez/jan * Flumotion/flumotion@2a6b048 * GitHub
    oder
    When to not just use socket.close() << Python recipes << ActiveState Code
    nicht was machen?
    Receiver/TV:
    • Vu+ Duo² 4xDVB-S2 / 2x-C / 1.8TB / OpenATV 6.1@Samsung 50" Plasma
    • AX QuadBox HD2400 2xDVB-S2 / 2x-C / 930 GB / OpenATV 6.1@Samsung 32" TFT
    • 2x Vu+ Solo² / OpenATV 6.1
    • S2-Twin-Tuner PCIe@Samsung SyncMaster T240HD (PC)
    • TechniSat SkyStar HD 2 (2.PC)
    Pay-TV: Schwarzfunk, Redlight HD Mega, XXL, HD-, Sky
    Internet: Unitymedia 1play 100 / Cisco EPC3212 + Linksys WRT1900ACS / IPv4 (UM) + IPv6 (HE)

  3. #53
    Avatar von SpaceRat
    Registriert seit
    13.08.2013
    Ort
    Midgard
    Beiträge
    2.725
    Total Downloaded
    745,74 MB
    Total Downloaded
    745,74 MB
    ReceiverDankeAktivitäten
    Box 1:
    Vu+ Duo² 4x DVB-S2 OpenATV 6.1
     
     
    Box 2:
    AX QuadBox 2xDVB-S2 OpenATV 6.1
     
     
    Box 3:
    2x Vu+ Solo² OpenATV 6.1
     
     
    Box 4:
    Topfield TF7700 HDPVR HDMU
     
     
    Box 5:
    DVBViewer
     
     
    Das hier war eine Änderung in stream.py, die zumindest einen Crash/Hänger in E2 verhindert hat:

    Code:
     	def requestWrite(self, notused1 = None, notused2 = None):
      		converter_args = []
      		self.converter = Streaming(converter_args)
     -		self.converter.source = self
     -		self.request.write(self.converter.getText())
     +		if self.converter:
     +			self.converter.source = self
     +			try:
     +				self.request.write(self.converter.getText())
     +			except:
     +				return
      
      class StreamController(resource.Resource):
      	def __init__(self, session, path = ""):
    Vielleicht muß da einfach was anderes bei "except:" passieren als "return"?
    Receiver/TV:
    • Vu+ Duo² 4xDVB-S2 / 2x-C / 1.8TB / OpenATV 6.1@Samsung 50" Plasma
    • AX QuadBox HD2400 2xDVB-S2 / 2x-C / 930 GB / OpenATV 6.1@Samsung 32" TFT
    • 2x Vu+ Solo² / OpenATV 6.1
    • S2-Twin-Tuner PCIe@Samsung SyncMaster T240HD (PC)
    • TechniSat SkyStar HD 2 (2.PC)
    Pay-TV: Schwarzfunk, Redlight HD Mega, XXL, HD-, Sky
    Internet: Unitymedia 1play 100 / Cisco EPC3212 + Linksys WRT1900ACS / IPv4 (UM) + IPv6 (HE)

  4. #54
    Avatar von betacentauri
    Registriert seit
    15.06.2013
    Beiträge
    1.799
    Total Downloaded
    1,32 MB
    Total Downloaded
    1,32 MB
    ReceiverDankeAktivitäten
    Box 1:
    ET-9200
     
     
    Box 2:
    ET-10000
     
     
    Box 3:
    ET-8500
     
     
    Box 4:
    ET-8000
     
     
    Box 5:
    Gigablue Quad+
     
     
    Ich hab es aber gerade ausprobiert. Auf meinem Ubuntu mit Twisted 13.x bekomme ich eine Exception, wenn der Webbrowser die Verbindung beendet:
    Code:
    Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
    [GCC 4.8.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from twisted.web.resource import Resource
    >>> from twisted.web import server
    >>> from twisted.internet import reactor
    >>> from twisted.python.util import println
    >>> 
    >>> class ExampleResource(Resource):
    ...     isLeaf = True
    ...     def render_GET(self, request):
    ...         request.write(b"hello world")
    ...         d = request.notifyFinish()
    ...         d.addCallback(lambda _: println("finished normally"))
    ...         d.addErrback(println, "error")
    ...         return server.NOT_DONE_YET
    ... 
    >>> resource = ExampleResource()
    >>> if __name__ == '__main__':
    ...     reactor.listenTCP(11111, server.Site(ExampleResource()))
    ...     reactor.run()
    ... 
    <<class 'twisted.internet.tcp.Port'> of twisted.web.server.Site on 11111>
    [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone'>: Connection was closed cleanly.
    ] error
    Auf der Box dagegen passiert nichts:
    Code:
    Python 2.7.11 (default, Aug 28 2016, 17:41:24) 
    [GCC 5.3.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> from twisted.web.resource import Resource
    >>> from twisted.web import server
    >>> from twisted.internet import reactor
    :0: UserWarning: You do not have a working installation of the service_identity module: 'No module named service_identity'.  Please install it from <https://pypi.python.org/pypi/service_identity> and make sure all of its dependencies are satisfied.  Without the service_identity module and a recent enough pyOpenSSL to support it, Twisted can perform only rudimentary TLS client hostname verification.  Many valid certificate/hostname mappings may be rejected.
    >>> from twisted.python.util import println
    >>> 
    >>> class ExampleResource(Resource):
    ...     isLeaf = True
    ...     def render_GET(self, request):
    ...         request.write(b"hello world")
    ...         d = request.notifyFinish()
    ...         d.addCallback(lambda _: println("finished normally"))
    ...         d.addErrback(println, "error")
    ...         return server.NOT_DONE_YET
    ... 
    >>> resource = ExampleResource()
    >>> if __name__ == '__main__':
    ...     reactor.listenTCP(9999, server.Site(ExampleResource()))
    ...     reactor.run()
    ... 
    <<class 'twisted.internet.tcp.Port'> of twisted.web.server.Site on 9999>

    Nochmal das hier bringt gar nichts in unserer Situation:
    request.notifyFinish().addCallback(self.close, None)
    request.notifyFinish().addErrback(self.close, None)

    Damit die Callbacks aufgerufen werden, muss irgendwer request.finish() aufrufen. Das macht aber keiner! Das wird weder vom WebIf selber aufgerufen noch automatisch dadurch, dass der Proxy sich beendet.

    Was 2014 irgendwer berichtet hat oder nicht, ist mir egal (vielleicht war der gleiche Fehler ja schon mal in einer Twisted Version und wurde behoben). Fakt ist, dass es mit Twisted 13.x funktioniert und mit 16.x nicht.
    ET-10000, ET-9200, ET-8000, Gigablue Quad+

  5. #55
    Avatar von SpaceRat
    Registriert seit
    13.08.2013
    Ort
    Midgard
    Beiträge
    2.725
    Total Downloaded
    745,74 MB
    Total Downloaded
    745,74 MB
    ReceiverDankeAktivitäten
    Box 1:
    Vu+ Duo² 4x DVB-S2 OpenATV 6.1
     
     
    Box 2:
    AX QuadBox 2xDVB-S2 OpenATV 6.1
     
     
    Box 3:
    2x Vu+ Solo² OpenATV 6.1
     
     
    Box 4:
    Topfield TF7700 HDPVR HDMU
     
     
    Box 5:
    DVBViewer
     
     
    Die Stelle hier:
    Code:
     	def requestWrite(self, notused1 = None, notused2 = None):
      		converter_args = []
      		self.converter = Streaming(converter_args)
     -		self.converter.source = self
     -		self.request.write(self.converter.getText())
     +		if self.converter:
     +			self.converter.source = self
     +			try:
     +				self.request.write(self.converter.getText())
     +			except:
     +				return
      
      class StreamController(resource.Resource):
      	def __init__(self, session, path = ""):
    wird aber im Fehlerfall auf jeden Fall aufgerufen, sonst hätte es da ja vorher nicht geknallt.

    D.h. wir landen auf jedem Fall im Fehlerfall nun bei "return".
    Man muß doch an dieser Stelle irgendwie die Verbindung terminieren können!?
    Receiver/TV:
    • Vu+ Duo² 4xDVB-S2 / 2x-C / 1.8TB / OpenATV 6.1@Samsung 50" Plasma
    • AX QuadBox HD2400 2xDVB-S2 / 2x-C / 930 GB / OpenATV 6.1@Samsung 32" TFT
    • 2x Vu+ Solo² / OpenATV 6.1
    • S2-Twin-Tuner PCIe@Samsung SyncMaster T240HD (PC)
    • TechniSat SkyStar HD 2 (2.PC)
    Pay-TV: Schwarzfunk, Redlight HD Mega, XXL, HD-, Sky
    Internet: Unitymedia 1play 100 / Cisco EPC3212 + Linksys WRT1900ACS / IPv4 (UM) + IPv6 (HE)

  6. #56
    Avatar von betacentauri
    Registriert seit
    15.06.2013
    Beiträge
    1.799
    Total Downloaded
    1,32 MB
    Total Downloaded
    1,32 MB
    ReceiverDankeAktivitäten
    Box 1:
    ET-9200
     
     
    Box 2:
    ET-10000
     
     
    Box 3:
    ET-8500
     
     
    Box 4:
    ET-8000
     
     
    Box 5:
    Gigablue Quad+
     
     
    Zitat Zitat von SpaceRat Beitrag anzeigen
    Das hier war eine Änderung in stream.py, die zumindest einen Crash/Hänger in E2 verhindert hat:

    Code:
         def requestWrite(self, notused1 = None, notused2 = None):
              converter_args = []
              self.converter = Streaming(converter_args)
     -        self.converter.source = self
     -        self.request.write(self.converter.getText())
     +        if self.converter:
     +            self.converter.source = self
     +            try:
     +                self.request.write(self.converter.getText())
     +            except:
     +                return
      
      class StreamController(resource.Resource):
          def __init__(self, session, path = ""):
    Vielleicht muß da einfach was anderes bei "except:" passieren als "return"?
    Damit bekomme ich einen netten Crash:
    Code:
    20:07:27.496 bsod.cpp:304 oops PC: 004cd10c
    20:07:27.496 bsod.cpp:310 oops 00000000 00000001 00000000 00000003
    20:07:27.496 bsod.cpp:310 oops 00000000 00000001 007242c8 00000003
    20:07:27.496 bsod.cpp:310 oops 00000001 005c1598 00000000 70206f6e
    20:07:27.496 bsod.cpp:310 oops 7fa7d6a0 0000005a 00000001 00720000
    20:07:27.496 bsod.cpp:310 oops 015d2dec 0156d8e0 7fa7e5e0 00000012
    20:07:27.496 bsod.cpp:310 oops 7fa7f718 00000001 006372e0 7fa7f89c
    20:07:27.496 bsod.cpp:310 oops 00723dfc 7715efa0 fefefeff 00000000
    20:07:27.497 bsod.cpp:310 oops 77184020 7fa7e530 7fa7f7c0 004cd988
    20:07:27.498 bsod.cpp:327 print_backtrace Backtrace:
    20:07:27.498 bsod.cpp:335 print_backtrace enigma2(_Z17handleFatalSignaliP9siginfo_tPv) [0x46B42C]
    20:07:27.498 bsod.cpp:335 print_backtrace enigma2(_ZN21eDVBServicePMTHandler17registerCAServiceEv) [0x4CD10E]
    20:07:27.499 bsod.cpp:335 print_backtrace enigma2(_ZN21eDVBServicePMTHandler8PMTreadyEi) [0x4CD988]
    20:07:27.499 bsod.cpp:335 print_backtrace enigma2(_ZN4SigC7Signal1IviNS_7MarshalIvEEE5emit_ERKiPv) [0x4824F0]
    20:07:27.499 bsod.cpp:335 print_backtrace enigma2(n/a) [0x4D271C]
    20:07:27.500 bsod.cpp:335 print_backtrace enigma2(_ZN4SigC7Signal1IviNS_7MarshalIvEEE5emit_ERKiPv) [0x4824F0]
    20:07:27.500 bsod.cpp:335 print_backtrace enigma2(_ZN4SigC7Signal1IvPKhNS_7MarshalIvEEE5emit_ERKS2_Pv) [0x49D384]
    20:07:27.500 bsod.cpp:335 print_backtrace enigma2(_ZN17eDVBSectionReader4dataEi) [0x49C664]
    20:07:27.500 bsod.cpp:335 print_backtrace enigma2(_ZN4SigC7Signal1IvPKcNS_7MarshalIvEEE5emit_ERKS2_Pv) [0x470A70]
    20:07:27.501 bsod.cpp:335 print_backtrace enigma2(n/a) [0x470BC0]
    20:07:27.501 bsod.cpp:335 print_backtrace enigma2(_ZN9eMainloop15processOneEventEjPP7_object9ePyObject) [0x4716B0]
    20:07:27.501 bsod.cpp:335 print_backtrace enigma2(_ZN9eMainloop7iterateEjPP7_object9ePyObject) [0x4719B8]
    20:07:27.502 bsod.cpp:335 print_backtrace enigma2(_ZN9eMainloop4pollE9ePyObjectS0_) [0x471AF8]
    20:07:27.502 bsod.cpp:347 handleFatalSignal -------FATAL SIGNAL

    Ach ne. Sorry hab das so gemacht:
    Code:
            def requestWrite(self, notused1 = None, notused2 = None):                                             
                    converter_args = []                            
                    self.converter = Streaming(converter_args)                   
                    self.converter.source = self                       
                    try:                                                                                          
                            self.request.write(self.converter.getText())
                            self.request.finish()                                
                    except:                                             
                            return
    ET-10000, ET-9200, ET-8000, Gigablue Quad+

  7. #57
    Avatar von SpaceRat
    Registriert seit
    13.08.2013
    Ort
    Midgard
    Beiträge
    2.725
    Total Downloaded
    745,74 MB
    Total Downloaded
    745,74 MB
    ReceiverDankeAktivitäten
    Box 1:
    Vu+ Duo² 4x DVB-S2 OpenATV 6.1
     
     
    Box 2:
    AX QuadBox 2xDVB-S2 OpenATV 6.1
     
     
    Box 3:
    2x Vu+ Solo² OpenATV 6.1
     
     
    Box 4:
    Topfield TF7700 HDPVR HDMU
     
     
    Box 5:
    DVBViewer
     
     
    Mit dieser Variante hängt nun auch der streamproxy viel länger *vbeg*:
    Code:
    	def requestWrite(self, notused1 = None, notused2 = None):
    		converter_args = []
    		self.converter = Streaming(converter_args)
    		if self.converter:
    			self.converter.source = self
    			try:
    				self.request.write(self.converter.getText())
    			except:
    				try:
    					self.request.close()
    				finally:
    					self.request = None
    					self.request.finish()
    					self._finished = True
    Also ich behaupte, wenn man da die richtigen Anweisungen einbaut, dann steckt dort die Lösung.
    Ich könnte da jetzt aber nur stundenlang raten ...
    Receiver/TV:
    • Vu+ Duo² 4xDVB-S2 / 2x-C / 1.8TB / OpenATV 6.1@Samsung 50" Plasma
    • AX QuadBox HD2400 2xDVB-S2 / 2x-C / 930 GB / OpenATV 6.1@Samsung 32" TFT
    • 2x Vu+ Solo² / OpenATV 6.1
    • S2-Twin-Tuner PCIe@Samsung SyncMaster T240HD (PC)
    • TechniSat SkyStar HD 2 (2.PC)
    Pay-TV: Schwarzfunk, Redlight HD Mega, XXL, HD-, Sky
    Internet: Unitymedia 1play 100 / Cisco EPC3212 + Linksys WRT1900ACS / IPv4 (UM) + IPv6 (HE)

  8. #58
    Avatar von betacentauri
    Registriert seit
    15.06.2013
    Beiträge
    1.799
    Total Downloaded
    1,32 MB
    Total Downloaded
    1,32 MB
    ReceiverDankeAktivitäten
    Box 1:
    ET-9200
     
     
    Box 2:
    ET-10000
     
     
    Box 3:
    ET-8500
     
     
    Box 4:
    ET-8000
     
     
    Box 5:
    Gigablue Quad+
     
     
    Damit schmiert E2 nicht mehr ab.

    Sieht aber komisch aus:
    self.request = None
    self.request.finish()

    Finally wird wohl nicht aufgerufen...


    Selbst wenn wir es schaffen self.request.finish() aufzurufen ohne, dass E2 danach crashed, haben wir trotzdem ein Problem. Dann werden nämlich die Callbacks von notifyFinish() aufgerufen (=self.close()) und der Stream gestoppt. Ist also alles Mist
    ET-10000, ET-9200, ET-8000, Gigablue Quad+

  9. #59
    Avatar von SpaceRat
    Registriert seit
    13.08.2013
    Ort
    Midgard
    Beiträge
    2.725
    Total Downloaded
    745,74 MB
    Total Downloaded
    745,74 MB
    ReceiverDankeAktivitäten
    Box 1:
    Vu+ Duo² 4x DVB-S2 OpenATV 6.1
     
     
    Box 2:
    AX QuadBox 2xDVB-S2 OpenATV 6.1
     
     
    Box 3:
    2x Vu+ Solo² OpenATV 6.1
     
     
    Box 4:
    Topfield TF7700 HDPVR HDMU
     
     
    Box 5:
    DVBViewer
     
     
    Zitat Zitat von betacentauri Beitrag anzeigen
    Selbst wenn wir es schaffen self.request.finish() aufzurufen ohne, dass E2 danach crashed, haben wir trotzdem ein Problem. Dann werden nämlich die Callbacks von notifyFinish() aufgerufen (=self.close()) und der Stream gestoppt. Ist also alles Mist
    Wieso?
    Das ist doch genau das, was wir wollen!

    Während des Streamings:
    Code:
    root@solo2se / # netstat -tupen | grep ":80 "
    tcp        0      0 127.0.0.1:48367         127.0.0.1:80            ESTABLISHED 566/streamproxy
    tcp        0      0 ::ffff:127.0.0.1:80     ::ffff:127.0.0.1:48367  ESTABLISHED 32693/enigma2
    Nach dem Streaming:
    Code:
    root@solo2se / # netstat -tupen | grep ":80 "
    tcp        0      0 127.0.0.1:48367         127.0.0.1:80            FIN_WAIT2   -
    tcp        1      0 ::ffff:127.0.0.1:80     ::ffff:127.0.0.1:48367  CLOSE_WAIT  32693/enigma2
    Nach Ablauf von FIN_WAIT2:
    Code:
    root@solo2se / # netstat -tupen | grep ":80 "
    tcp        1      0 ::ffff:127.0.0.1:80     ::ffff:127.0.0.1:48367  CLOSE_WAIT  32693/enigma2
    Solange gestreamed wird, bleibt die Session offen und der Fehlerfall tritt gar nicht ein!
    Receiver/TV:
    • Vu+ Duo² 4xDVB-S2 / 2x-C / 1.8TB / OpenATV 6.1@Samsung 50" Plasma
    • AX QuadBox HD2400 2xDVB-S2 / 2x-C / 930 GB / OpenATV 6.1@Samsung 32" TFT
    • 2x Vu+ Solo² / OpenATV 6.1
    • S2-Twin-Tuner PCIe@Samsung SyncMaster T240HD (PC)
    • TechniSat SkyStar HD 2 (2.PC)
    Pay-TV: Schwarzfunk, Redlight HD Mega, XXL, HD-, Sky
    Internet: Unitymedia 1play 100 / Cisco EPC3212 + Linksys WRT1900ACS / IPv4 (UM) + IPv6 (HE)

  10. #60
    Avatar von SpaceRat
    Registriert seit
    13.08.2013
    Ort
    Midgard
    Beiträge
    2.725
    Total Downloaded
    745,74 MB
    Total Downloaded
    745,74 MB
    ReceiverDankeAktivitäten
    Box 1:
    Vu+ Duo² 4x DVB-S2 OpenATV 6.1
     
     
    Box 2:
    AX QuadBox 2xDVB-S2 OpenATV 6.1
     
     
    Box 3:
    2x Vu+ Solo² OpenATV 6.1
     
     
    Box 4:
    Topfield TF7700 HDPVR HDMU
     
     
    Box 5:
    DVBViewer
     
     
    Ist es eigentlich der request, der finished/closed werden muß oder die session?
    Nach meinem bescheidenen Kenntnisstand doch die Session, oder?
    Receiver/TV:
    • Vu+ Duo² 4xDVB-S2 / 2x-C / 1.8TB / OpenATV 6.1@Samsung 50" Plasma
    • AX QuadBox HD2400 2xDVB-S2 / 2x-C / 930 GB / OpenATV 6.1@Samsung 32" TFT
    • 2x Vu+ Solo² / OpenATV 6.1
    • S2-Twin-Tuner PCIe@Samsung SyncMaster T240HD (PC)
    • TechniSat SkyStar HD 2 (2.PC)
    Pay-TV: Schwarzfunk, Redlight HD Mega, XXL, HD-, Sky
    Internet: Unitymedia 1play 100 / Cisco EPC3212 + Linksys WRT1900ACS / IPv4 (UM) + IPv6 (HE)


Seite 6 von 8 ErsteErste ... 45678 LetzteLetzte

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  
Diese Website benutzt Cookies
Wir benutzen Cookies um Sitzungsinformationen zu speichern. Dies erleichtert es uns z.B. Dich an Deine Login zu erinnern, Einstellungen der Webseite zu speichern, Inhalte und Werbung zu personalisieren, Social Media Funktionen anzubieten und unser Datenaufkommen zu analysieren. Wir teilen diese Informationen ebenfalls mit unseren Social Media-, Werbe- und Analysepartnern.
     
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:52 Uhr.
Powered by vBulletin® Version 4.2.5 (Deutsch)
Copyright ©2018 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.
Resources saved on this page: MySQL 11,76%
Parts of this site powered by vBulletin Mods & Addons from DragonByte Technologies Ltd. (Details)
vBulletin Skin By: PurevB.com