001package Torello.HTML.Tools.Images;
002
003import Torello.HTML.*;
004import Torello.Java.*;
005
006import Torello.Java.Additional.Ret2;
007import Torello.JavaDoc.LinkJavaSource;
008
009import java.util.function.*;
010
011import java.io.Serializable;
012import java.io.File;
013
014import java.net.URL;
015import java.net.MalformedURLException;
016
017import java.util.Vector;
018import java.util.Objects;
019import java.util.concurrent.TimeUnit;
020import java.util.regex.Matcher;
021
022
023/**
024 * Holds all relevant configurations and parameters needed to run the primary download-loop of
025 * class {@link ImageScraper}
026 * 
027 * <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST>
028 * <EMBED CLASS='external-html' DATA-FILE-ID=REQ_STR_BUILDER1_EX>
029 */
030@SuppressWarnings("overrides")
031@Torello.JavaDoc.JDHeaderBackgroundImg(EmbedTagFileID="IMAGE_SCRAPER_CLASS")
032public class Request implements Cloneable, Serializable
033{
034    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
035    public static final long serialVersionUID = 1;
036
037
038    // ********************************************************************************************
039    // ********************************************************************************************
040    // MAIN CONSTRUCTORS
041    // ********************************************************************************************
042    // ********************************************************************************************
043
044
045    // There are 5 or 6 'static' builder-methods below.  The only reason on earth that those are
046    // static-methods rather than constructors is that their parameter lists all use the same
047    // 'Iterable', but with a different Generic-Parameter.  If you convert those to Constructors,
048    // you will get that they have the "Same Erasure", and that compiling cannot continue.
049    //
050    // Instead they are methods that have slightly different names, and the Java-Compiler, instead,
051    // shuts up, and stops complaining.
052
053    Request(
054            Vector<URL> source, int size, URL originalPageURL, Vector<String[]> b64Images,
055            Vector<Exception> tagNodeSRCExceptions
056        )
057    {
058        this.source                 = source;
059        this.size                   = size;
060        this.counterPrinter         = getPrinter(size);
061        this.originalPageURL        = originalPageURL;
062        this.b64Images              = b64Images;
063        this.tagNodeSRCExceptions   = tagNodeSRCExceptions;
064    }
065
066    Request(Vector<URL> source, int size, URL originalPageURL)
067    {
068        this.source                 = source;
069        this.size                   = size;
070        this.counterPrinter         = getPrinter(size);
071        this.originalPageURL        = originalPageURL;
072        this.b64Images              = null;
073        this.tagNodeSRCExceptions   = null;
074    }
075
076    // Used by Clone
077    private Request(final Request other)
078    {
079        this.source                 = other.source;
080        this.size                   = other.size;
081        this.counterPrinter         = other.counterPrinter;
082        this.originalPageURL        = other.originalPageURL;
083        this.b64Images              = other.b64Images;
084        this.tagNodeSRCExceptions   = other.tagNodeSRCExceptions;
085        this.b64Pos                 = other.b64Pos;
086        this.tnExPos                = other.tnExPos;
087    }
088
089
090    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
091    // Small static constructor-helper
092    // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
093
094    private static IntFunction<String> getPrinter(int size)
095    {
096        // Now produce the Printer for the Image-Number.  All this does is make sure to do an
097        // appropriate zero-padding for the text-output.
098
099        if      (size < 10)     return (int i) -> "" + i;
100        else if (size < 100)    return StrPrint::zeroPad10e2;
101        else if (size < 1000)   return StrPrint::zeroPad;
102        else if (size < 10000)  return StrPrint::zeroPad10e4;
103
104        // This case seems extremely unlikely and even largely preposterous, but leaving it like
105        // this means I will never have to analyze this crap ever again.  Note that the above case
106        // where size is greater than 1,000 seems a little ridiculous.  Usually there are under 100
107        // photos on any one HTML Page.
108
109        else
110        {
111            final int power = (int) Math.floor(Math.log10(size));
112            return (int i) -> StrPrint.zeroPad(i, power);
113        }
114    }
115
116
117    // ********************************************************************************************
118    // ********************************************************************************************
119    // Static Constructor-Like Builder Methods (Cannot Use Constructors because of "Erasure")
120    // ********************************************************************************************
121    // ********************************************************************************************
122
123
124    /**
125     * Builds an instance of this class from a list of {@code URL's} as {@code String's}
126     * 
127     * @param source <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ITER_STR>
128     * 
129     * @return A {@code 'Request'} instance.  This may be further configured by assigning values to
130     * any / all fields (which will still have their initialized / default-values)
131     * 
132     * @throws NullPointerException If any of the {@code String's} in the {@code Iterable} are null
133     * 
134     * @throws IllegalArgumentException If any of the {@code URL's} are {@code String's} which
135     * begin with neither {@code 'http://'} nor {@code 'https://'}.  Since this method doesn't
136     * accept the parameter {@code 'originalPageURL'}, each and every {@code URL} in the 
137     * {@code 'source'} iterable must be a full &amp; complete {@code URL}.
138     * 
139     * <BR /><BR />This exception will also throw if there are any {@code URL's} in the
140     * {@code String}-List that cause a {@code MalformedURLException} to throw when constructing an
141     * instance of {@code java.net.URL} from the {@code String}.  In these cases, the original
142     * {@code MalformedURLException} will be assigned to the {@code 'cause'}, and may be retrieved
143     * using the exception's {@code getCause()} method.
144     */
145    @LinkJavaSource(handle="FromStringIterator", name="build", paramCount=1)
146    public static Request buildFromStrIter(Iterable<String> source)
147    { return FromStringIterator.build(source); }
148
149    /**
150     * Builds an instance of this class from a list of {@code URL's} as {@code String's}
151     * 
152     * @param source <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ITER_STR>
153     * @param originalPageURL <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ORIG_PG_URL>
154     * 
155     * @param skipDontThrowIfBadStr If an exception is thrown when attempting to resolve a
156     * partial-{@code URL}, and this parameter is {@code TRUE}, then that exception is suppressed
157     * and logged, and the builder-loop continues to the next {@code URL}-as-a-{@code String}.
158     * 
159     * <BR /><BR />When this parameter is passed {@code FALSE}, unresolvable {@code URL's} will
160     * generate an {@code IllegalArgumentException}-throw.
161     * 
162     * <BR /><BR />Note that the presence of a null in the {@code Iterable 'source'} parameter
163     * will always force this method to throw {@code NullPointerException}.
164     * 
165     * @return A {@code 'Request'} instance.  This may be further configured by assigning values to
166     * any / all fields (which will still have their initialized / default-values)
167     * 
168     * @throws NullPointerException If any of the {@code String's} in the {@code Iterable} are null
169     * 
170     * @throws IllegalArgumentException This exception will also throw if there are any
171     * {@code URL's} in the {@code String}-List that cause a {@code MalformedURLException} to throw
172     * when constructing an instance of {@code java.net.URL} from the {@code String}.  In these
173     * cases, the generated {@code MalformedURLException} will be assigned to the exception's
174     * {@code 'cause'}, and may therefore be retrieved using this exception's {@code getCause()}
175     * method.
176     */
177    @LinkJavaSource(handle="FromStringIterator", name="build", paramCount=3)
178    public static Request buildFromStrIter
179        (Iterable<String> source, URL originalPageURL, boolean skipDontThrowIfBadStr)
180    { return FromStringIterator.build(source, originalPageURL, skipDontThrowIfBadStr); }
181
182    /**
183     * Builds an instance of this class using the {@code SRC}-Attribute from a list of
184     * {@link TagNode}'s.
185     * 
186     * @param source <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ITER_TGND>
187     * 
188     * @param originalPageURL <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ORIG_PG_URL>
189     *
190     * @param skipDontThrowIfBadSRCAttr
191     * <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_SKIP_BOOL>
192     * 
193     * @return A {@code 'Request'} instance.  This may be further configured by assigning values to
194     * any / all fields (which will still have their initialized / default-values)
195     * 
196     * @throws NullPointerException If any of the {@link TagNode}'s in the {@code Iterable} are
197     * null
198     * 
199     * @throws SRCException If any of the {@link TagNode}'s in the list do not have a {@code 'SRC'}
200     * Attribute, and {@code 'skipDontThrowIfBadSRCAttr'} is {@code FALSE}.
201     * 
202     * <BR /><BR />This exception will also throw if there are any {@code URL's} in the
203     * {@link TagNode}-List that cause a {@code MalformedURLException} to throw when constructing
204     * an instance of {@code java.net.URL} (from the {@code TagNode's SRC}-Attribute).  In these
205     * cases, the generated {@code MalformedURLException} will be assigned to the exception's
206     * {@code 'cause'}, and may therefore be retrieved using the exception's {@code getCause()}
207     * method.
208     *
209     * <BR /><BR />If {@code 'skipDontThrowIfBadSRCAttr'} is {@code FALSE}, then this
210     * exception will not throw, and a null will be placed in the query-list.
211     */
212    @LinkJavaSource(handle="FromTagNodeIterator", name="build", paramCount=3)
213    public static Request buildFromTagNodeIter
214        (Iterable<TagNode> source, URL originalPageURL, boolean skipDontThrowIfBadSRCAttr)
215    { return FromTagNodeIterator.build(source, originalPageURL, skipDontThrowIfBadSRCAttr); }
216
217    /**
218     * Builds an instance of this class using the {@code SRC}-Attribute from a list of
219     * {@link TagNode}'s.
220     * 
221     * @param source <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ITER_TGND>
222     *
223     * @param skipDontThrowIfBadSRCAttr
224     * <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_SKIP_BOOL>
225     * 
226     * @return A {@code 'Request'} instance.  This may be further configured by assigning values to
227     * any / all fields (which will still have their initialized / default-values)
228     * 
229     * @throws NullPointerException If any of the {@link TagNode}'s in the {@code Iterable} are
230     * null
231     * 
232     * @throws SRCException If any of the {@link TagNode}'s in the list do not have a
233     * {@code 'SRC'}-Attribute, and {@code 'skipDontThrowIfBadSRCAttr'} is {@code FALSE}.
234     * 
235     * <BR /><BR />This exception will also throw if any of the {@code URL's} assigned to a
236     * {@code 'SRC'}-Attribute are partial-{@code URL's} which do not begin with {@code 'http://'}
237     * (or {@code 'https://'}), and {@code 'skipDontThrowIfBadSRCAttr'} is {@code FALSE}.
238     * 
239     * <BR /><BR />Finally, if any of the {@code URL's} inside a {@link TagNode}'s'
240     * {@code 'SRC'}-Attribute cause a {@code MalformedURLException}, that exception will be
241     * assigned to the {@code cause} of a {@link SRCException}, and thrown (unless
242     * {@code 'skipDontThrowIfBadSRCAttr'} is {@code FALSE}).
243     */
244    @LinkJavaSource(handle="FromTagNodeIterator", name="build", paramCount=2)
245     public static Request buildFromTagNodeIter
246        (Iterable<TagNode> source, boolean skipDontThrowIfBadSRCAttr)
247    { return FromTagNodeIterator.build(source, skipDontThrowIfBadSRCAttr); }
248
249    /**
250     * Builds an instance of this class using a list of <I><B STYLE='color: red;'>already
251     * prepared</B></I> {@code URL's}.
252     * 
253     * @param source <EMBED CLASS='external-html' DATA-FILE-ID=REQUEST_ITER_URL>
254     * 
255     * @return A {@code 'Request'} instance.  This may be further configured by assigning values to
256     * any / all fields (which will still have their initialized / default-values)
257     * 
258     * @throws NullPointerException If any of the {@code URL's} in the {@code Iterable} are null
259     */
260    @LinkJavaSource(handle="FromURLIterator")
261    public static Request buildFromURLIter(Iterable<URL> source)
262    { return FromURLIterator.build(source); }
263
264
265    // ********************************************************************************************
266    // ********************************************************************************************
267    // Package-Visible Utility Methods for ImageScraper, Set by the Constructor.
268    // ********************************************************************************************
269    // ********************************************************************************************
270
271
272    // Package-Visibility: Used only in class ImageScraper (to retrieve the Iterable)
273    Iterable<URL> source() { return source; }
274
275    // This Vector-Index Counter is used only once - three lines below
276    private int b64Pos = 0;
277
278    // Package-Visibility: Used only in class Imagescraper (to retrieve a B64-Image String-Array)
279    String[] nextB64Image()
280    {
281        // Since the creation/construction of these Vectors is completely controlled, they should
282        // never be a source of NullPointerException.  If for some odd reason they are, it is
283        // better to keep a record indicating that "this really shouldn't have happened"
284        //
285        // These are "assert" statements.  There is no reason this method should ever be called
286        // if these are null.  In the static-builder, if a null-URL is put into the source-vector
287        // then one of these would be called (b64Images and/or tagNodeSRCExceptions).  In such
288        // cases, both of these secondary vectors would already have references put into them.
289        //
290        // Since the "ImageScraper" is heavy-user-interaction class, the paranoia is 10x worse.
291        // This sort of helps mitigate it, although it seems completely superfluous and unnecessary
292
293        if (b64Images == null)          throw new UnreachableError();
294        if (b64Pos >= b64Images.size()) throw new UnreachableError();
295
296        return b64Images.elementAt(b64Pos++);
297    }
298
299    // This Vector-Index Counter is used only once - three lines below
300    private int tnExPos = 0;
301
302    // Package-Visibility: Used only by class ImageScraper
303    Exception nextTNSRCException()
304    {
305        // Since the creation/construction of these Vectors is completely controlled, they should
306        // never be a source of NullPointerException.  If for some odd reason they are, it is
307        // better to keep a record indicating that "this really shouldn't have happened"
308        //
309        // These are "assert" statements.  There is no reason this method should ever be called
310        // if these are null.  In the static-builder, if a null-URL is put into the source-vector
311        // then one of these would be called (b64Images and/or tagNodeSRCExceptions).  In such
312        // cases, both of these secondary vectors would already have references put into them.
313        //
314        // Since the "ImageScraper" is heavy-user-interaction class, the paranoia is 10x worse.
315        // This sort of helps mitigate it, although it seems completely superfluous and unnecessary
316
317        if (tagNodeSRCExceptions == null)           throw new UnreachableError();
318        if (tnExPos >= tagNodeSRCExceptions.size()) throw new UnreachableError();
319
320        return tagNodeSRCExceptions.elementAt(tnExPos++);
321    }
322
323
324    // ********************************************************************************************
325    // ********************************************************************************************
326    // Primary Request Fields
327    // ********************************************************************************************
328    // ********************************************************************************************
329 
330
331    /** {@code URL} from whence this page has been downloaded */
332    public final URL originalPageURL;
333
334    // The Source Iterable
335    private final Iterable<URL> source;
336
337    /** The number of Image-{@code URL's} identified inside the {@code 'source'} Iterable. */
338    public final int size;    
339
340
341    // This is just a zero-padding printer.  It adjusts for the number of elements in the original
342    // input Iterable.  If there are, for example, under 100 elements, then the first 10 elements
343    // will be padded with a zero.
344
345    final IntFunction<String> counterPrinter;
346
347    // Any & all Base-64 Images.  This is usually empty, so it is initialized to null
348    private final Vector<String[]> b64Images;
349
350
351    // If the user has built from an Iterable<TagNode>, and requested to suppress-exceptions, then
352    // this vector will save those exceptions so that they are ready for the return/result object.
353
354    private final Vector<Exception> tagNodeSRCExceptions;
355
356
357    // ********************************************************************************************
358    // ********************************************************************************************
359    // Public-Fields 01: Verbosity & URL-PreProcessor
360    // ********************************************************************************************
361    // ********************************************************************************************
362
363
364    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_verbosity>*/
365    public Verbosity verbosity = Verbosity.Normal;
366
367    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_urlPreProcessor>*/
368    public Function<URL, URL> urlPreProcessor = null;
369
370
371    // ********************************************************************************************
372    // ********************************************************************************************
373    // Public-Fields 02: Location-Decisions for Saving an Image File, or sending to 'imageReceiver'
374    // ********************************************************************************************
375    // ********************************************************************************************
376
377
378    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_targetDirectoryRetriever>*/
379    public Function<ImageInfo, File> targetDirectoryRetriever = null;
380
381    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_imageReceiver>*/
382    public Consumer<ImageInfo> imageReceiver = null;
383
384    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_targetDirectory>*/
385    public String targetDirectory = null;
386
387
388    // ********************************************************************************************
389    // ********************************************************************************************
390    // Public-Fields 03: File-Name given to an Image File
391    // ********************************************************************************************
392    // ********************************************************************************************
393
394
395    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_fileNamePrefix>*/
396    public String fileNamePrefix = null;
397
398    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_useDefaultCounterForImageFileNames>*/
399    public boolean useDefaultCounterForImageFileNames = true;
400
401    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_getImageFileSaveName>*/
402    public Function<ImageInfo, String> getImageFileSaveName = null;
403
404
405    // ********************************************************************************************
406    // ********************************************************************************************
407    // Public-Fields 04: BOOLEANS'S: Continuing or Throwing on Failure & Exception
408    // ********************************************************************************************
409    // ********************************************************************************************
410
411
412    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipOnDownloadException>*/
413    public boolean skipOnDownloadException = false;
414
415    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipOnB64DecodeException>*/
416    public boolean skipOnB64DecodeException = false;
417
418    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipOnTimeOutException>*/
419    public boolean skipOnTimeOutException = false;
420
421    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipOnNullImageException>*/
422    public boolean skipOnNullImageException = false;
423
424    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipOnImageWritingFail>*/
425    public boolean skipOnImageWritingFail = false;
426
427    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipOnUserLambdaException>*/
428    public boolean skipOnUserLambdaException = false;
429
430
431    // ********************************************************************************************
432    // ********************************************************************************************
433    // Public-Fields 05: USER-PREDICATE'S & BOOLEAN'S: Which Image Files to Save, and Which to Skip
434    // ********************************************************************************************
435    // ********************************************************************************************
436
437
438    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipURL>*/
439    public Predicate<URL> skipURL = null;
440
441    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_skipBase64EncodedImages> */
442    public boolean skipBase64EncodedImages = false;
443
444    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_keeperPredicate> */
445    public Predicate<ImageInfo> keeperPredicate = null;
446
447
448    // ********************************************************************************************
449    // ********************************************************************************************
450    // Public-Fields 06: Avoiding Hangs and Locks with a TimeOut
451    // ********************************************************************************************
452    // ********************************************************************************************
453
454
455    /**
456     * <EMBED CLASS='external-html' DATA-FILE-ID=REQ_MAX_WAIT_TIME>
457     * @see #MAX_WAIT_TIME_UNIT
458     * @see #maxDownloadWaitTime
459     */
460    public static final long MAX_WAIT_TIME = 10;
461
462    /**
463     * <EMBED CLASS='external-html' DATA-FILE-ID=REQ_MAX_WAIT_TIME_UNIT>
464     * @see #MAX_WAIT_TIME
465     * @see #waitTimeUnits
466     */
467    public static final TimeUnit MAX_WAIT_TIME_UNIT = TimeUnit.SECONDS;
468
469    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_maxDownloadWaitTime> */
470    public long maxDownloadWaitTime = MAX_WAIT_TIME;
471
472    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_waitTimeUnits> */
473    public TimeUnit waitTimeUnits = MAX_WAIT_TIME_UNIT;
474
475
476    // ********************************************************************************************
477    // ********************************************************************************************
478    // Public-Fields 07: USER-AGENT
479    // ********************************************************************************************
480    // ********************************************************************************************
481
482
483    /**
484     * <EMBED CLASS='external-html' DATA-FILE-ID=REQ_DEFAULT_USER_AGENT>
485     * @see Scrape#USER_AGENT;
486     */
487    public static final String DEFAULT_USER_AGENT = Scrape.USER_AGENT;
488
489    /**
490     * <EMBED CLASS='external-html' DATA-FILE-ID=REQ_userAgent>
491     * @see Scrape#DEFAULT_USER_AGENT;
492     */
493    public String userAgent = DEFAULT_USER_AGENT;
494
495    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_alwaysUseUserAgent> */
496    public boolean alwaysUseUserAgent = false;
497
498    /** <EMBED CLASS='external-html' DATA-FILE-ID=REQ_retryWithUserAgent> */
499    public boolean retryWithUserAgent = true;
500
501
502    // ********************************************************************************************
503    // ********************************************************************************************
504    // Check for Validity Method
505    // ********************************************************************************************
506    // ********************************************************************************************
507
508
509    void CHECK() { RequestValidity.check(this); }
510
511
512    // ********************************************************************************************
513    // ********************************************************************************************
514    // TURN ON **ALL** Exception-Skip Methods
515    // ********************************************************************************************
516    // ********************************************************************************************
517
518
519    /** This allows a user to quickly / easily set all {@code 'skipOn'} flags in one method call */
520    public void skipOnAllExceptions()
521    {
522        // exceptions thrown by Java's ImageIO class when downloading and image
523        skipOnDownloadException =
524
525            // if Java's Base-64 Image-Decoder throws an exception.
526            skipOnB64DecodeException =
527
528            // exception that's thrown when the Monitor-Thread has timed-out.
529            skipOnTimeOutException =
530
531            // exception that's thrown when a downloaded image is null.
532            skipOnNullImageException =
533
534            // exceptions thrown when writing an already downloaded image to the file-system.
535            skipOnImageWritingFail =
536
537            // exceptions thrown by any of the User-Provided Lambda-Target / Functional-Interfaces
538            skipOnUserLambdaException = true;
539    }
540
541
542    // ********************************************************************************************
543    // ********************************************************************************************
544    // Standard-Java Object Methods
545    // ********************************************************************************************
546    // ********************************************************************************************
547
548
549    /**
550     * Converts {@code 'this'} instance into a simple Java-{@code String}
551     * @return A {@code String} where each field has had a 'best efforts' {@code String}-Conversion
552     */
553    @LinkJavaSource(handle="RequestToString")
554    public String toString()
555    { return RequestToString.toString(this); }
556
557
558    // ********************************************************************************************
559    // ********************************************************************************************
560    // Clone & Clone-Constructor
561    // ********************************************************************************************
562    // ********************************************************************************************
563
564
565    /**
566     * Builds a clone of {@code 'this'} instance
567     * 
568     * @return The copied instance.  Note that this is a <B STYLE='color: red;'>shallow</B> clone,
569     * rather than a <B STYLE='color: red;'>deep</B> clone.  The references within the returned
570     * instances are <I>the exact same references as are in {@code 'this'} instance</I>.
571     */
572    @LinkJavaSource(handle="RequestClone")
573    public Request clone()
574    {
575        final Request cloned = new Request(this);
576        RequestClone.copy(this, cloned);
577        return cloned;
578    }
579
580}