Professional Web Applications Themes

Archiving large graphs (part II) - Mac Programming

Last September, I posted a question about archiving really big graphs without crashing: http://www.google.com/groups?hl=en&lr=&ie=UTF-8&selm=clund-D1FE69.12090 327092003%40amstwist00.chello.com Thanks to one very helpful poster, the problem was determined found to be never ending recursions, and the solution was to use NSKeyedArchiver instead of NSArchiver. This had to wait until I had upgraded to 10.3, but sure enough, that did the trick. That app would now archive very large graphs without crashing. Later on, I decided to turn this thing to a NSDoent app. Everything works fine, except that this crashing bug seems to have returned. The only difference is that now I'm crashing ...

  1. #1

    Default Archiving large graphs (part II)

    Last September, I posted a question about archiving really big graphs
    without crashing:

    http://www.google.com/groups?hl=en&lr=&ie=UTF-8&selm=clund-D1FE69.12090
    327092003%40amstwist00.chello.com

    Thanks to one very helpful poster, the problem was determined found to
    be never ending recursions, and the solution was to use
    NSKeyedArchiver instead of NSArchiver. This had to wait until I had
    upgraded to 10.3, but sure enough, that did the trick. That app would
    now archive very large graphs without crashing.

    Later on, I decided to turn this thing to a NSDoent app. Everything
    works fine, except that this crashing bug seems to have returned. The
    only difference is that now I'm crashing when I try to *load* large
    graphs. Small graphs work fine, large ones do not. And from what I can
    see in the debugger, the problem is once again caused by recursions -
    but now they happen when loading these huge graphs.

    The loading and saving is done in MyDoent with the two following
    methods:

    - (NSData *)dataRepresentationOfType:(NSString *)aType
    {
    return [NSKeyedArchiver archivedDataWithRootObject:theRoot];
    }

    - (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
    {
    theRoot = [[NSKeyedUnarchiver unarchiveObjectWithData:data]
    retain];
    return YES;
    }

    Other than that, the encoding/decoding methods are unchanged.

    Any ideas?

    --
    C Lund, www.notam02.no/~clund
    C Guest

  2. #2

    Default Re: Archiving large graphs (part II)

    In article <chello.com>,
    C Lund <no> wrote:
     

    This is your mistake, I think. A quick scan of the old thread indicated
    your decoded objects were not being retained. I forget if it was
    Panther or an earlier release that made a call to -retain explicit. If
    it's not crashing in small cases, it's probably just you getting lucky
    that memory isn't being overwritten. That my no-code guess; if you want
    better post the full methods you use for coding all objects in the graph.
    Doc Guest

  3. #3

    Default Re: Archiving large graphs (part II)

    In article
    <supernews.com 
    Doc O'Leary <example.com> wrote: [/ref]
     

    They were loaded straight into NSMutableArrays. I wouldn't think
    retains would be needed. I crash with a "signal 11 (SIGSEGV)" message,
    btw.
     

    It doesn't crash in the non-doent version of the app either.
     

    Ok. Here are the various initWithCoder methods:

    RootClass.m

    -(id)initWithCoder:(NSCoder *)coder
    {
    int i;
    int aListSize, bListSize;
    [coder decodeValueOfObjCType:encode(int) at:&theExtent];

    // aList = [[coder decodeObject] retain];
    // bList = [[coder decodeObject] retain];

    [coder decodeValueOfObjCType:encode(int) at:&aListSize];
    aList = [[NSMutableArray alloc] init];
    for (i=0;i<aListSize;i++)
    [aList addObject:[coder decodeObject]];

    [coder decodeValueOfObjCType:encode(int) at:&bListSize];
    bList = [[NSMutableArray alloc] init];
    for (i=0;i<bListSize;i++)
    [bList addObject:[coder decodeObject]];

    NSLog("- file loaded with extent = %i ------",theExtent);
    NSLog("aList has %i entries",[aList count]);
    NSLog("bList has %i entries",[bList count]);

    return self;
    }

    ClassA.m

    -(id)initWithCoder:(NSCoder *)coder
    {
    int i;
    int bListSize;
    bList = [[NSMutableArray alloc] init];

    [coder decodeValueOfObjCType:encode(int) at:&bListSize];
    for (i=0;i<bListSize;i++)
    [bList addObject:[coder decodeObject]];

    return self;
    }

    ClassB.m

    -(id)initWithCoder:(NSCoder *)coder
    {
    int i;
    int bListSize;

    aList = [[NSMutableArray alloc] init];
    bList = [[NSMutableArray alloc] init];

    for (i=0;i<3;i++)
    [aList addObject:[coder decodeObject]];
    [coder decodeValueOfObjCType:encode(int) at:&bListSize];
    for (i=0;i<bListSize;i++)
    [bList addObject:[coder decodeObject]];

    return self;
    }

    --
    C Lund, www.notam02.no/~clund
    C Guest

  4. #4

    Default Re: Archiving large graphs (part II)

    In article <chello.com>,
    C Lund <no> wrote:
     

    OK, I only caught the part of the thread that said you should just
    archive the array (i.e., the part that made sense). I don't understand
    why you decided to manually archive the array contents. It strikes me
    that it was a move to get things to "work" rather than finding and
    fixing a bug. Without a stack trace of where the crash actually occurs,
    it's hard to pin the NSCoding methods.
     

    Which further points away from the archiving code. But keep reading!
    :-)
     

    I see no appropriate super -init calls, especially -initWithCoder: since
    your names (RootClass, ClassA, ClassB) imply an inheritance. If they
    are subclasses, though, then I'm totally confused about why you would be
    archiving seemingly identical information in two places.

    At this point, I probably want to see a lot more code than you'd want to
    show. I suggest reading over Apple's doentation on archiving again,
    and revamping your code so that the array properly handles its own
    persistence.
    Doc Guest

  5. #5

    Default Re: Archiving large graphs (part II)

    In article
    <supernews.com 
    Doc O'Leary <example.com> wrote: 
    > OK, I only caught the part of the thread that said you should just
    > archive the array (i.e., the part that made sense). I don't understand
    > why you decided to manually archive the array contents. It strikes me
    > that it was a move to get things to "work" rather than finding and
    > fixing a bug.[/ref]

    It was an attempt at preventing recursive encoding. Didn't make any
    difference so I just left it that way.
     
     
    > Which further points away from the archiving code.[/ref]

    I agree - unless there's something about the doent architecture
    that fouls up the archiving.
     
     
    > I see no appropriate super -init calls, especially -initWithCoder: since
    > your names (RootClass, ClassA, ClassB) imply an inheritance. If they
    > are subclasses, though, then I'm totally confused about why you would be
    > archiving seemingly identical information in two places.[/ref]

    The code I posted was from a stripped down version of the "real" app
    I'm working on. ClassA & B are vertexes and surfaces, all of which are
    linked together - three vertexes pr surface and up to three surfaces
    and any number of vertexes pr surface. The result is a large, messy
    graph.

    In an attempt to isolate the problem, I reduced this to a simple
    application that creates this large messy graph, archives it, and then
    unarchives it.
     

    Want me to email you the stripped-down version of the project?
     

    I went through all that the last time I had this problem, but it
    wouldn't hurt to take another look I guess.

    --
    C Lund, www.notam02.no/~clund
    C Guest

  6. #6

    Default Re: Archiving large graphs (part II)

    In article <chello.com>,
    C Lund <no> wrote:
     

    If it didn't make a difference, you should have still went with the
    right way instead of doing it manually. NSArchiver doesn't have a
    (known) problem with recursive encoding (objects are uniqued in an
    archive); any advice you got in that matter should be disregarded.
     

    Trust me, there isn't. Having written custom NSCoder subclasses for
    STEnterprise, I ran into a lot of issues and none of them had to do with
    archive sizes. I'm talking about testing with hundreds of thousands of
    objects and archives of over 100MB.

    If you really can't pinpoint the exact cause of the crash, you need to
    look for problems in your own code before you point fingers. Apple can
    indeed have buggy code, but everything you've show points to errors on
    your part.
     

    When you fix the methods to call designated initializers as I noted,
    sure. If you're still having problems, that is.
    Doc Guest

  7. #7

    Default Re: Archiving large graphs (part II)

    On Tue, 22 Jun 2004, Doc O'Leary wrote:
     
    >
    > If it didn't make a difference, you should have still went with the
    > right way instead of doing it manually. NSArchiver doesn't have a
    > (known) problem with recursive encoding (objects are uniqued in an
    > archive); any advice you got in that matter should be disregarded.[/ref]

    That is not strictly true. Both NSArchiver and NSKeyedArchiver encode
    objects in a recursive fashion, so a large, complex object graph can cause
    the program to run out of stack space and crash. And, while it's possible
    to write an archiver that doesn't encode in a recursive fashion, it is
    impossible with the current API to write an unarchiver that doesn't decode
    recursively, so this is a problem that one simply must live with. In
    practical terms, you can archive a graph that's several thousand objects
    deep, and no more. I believe the code as given was a way to reduce the
    depth of the graph for a constant number of objects, which is not a good
    solution but could help make borderline cases work.

    The proper way of getting around this problem is to avoid situations where
    you have deep recursive archiving. If you have a complex graph, flatten it
    and archive the individual objects first, and archive the links between
    the objects using encodeConditionalObject: so that you won't trigger the
    recursive behavior.
    Michael Guest

  8. #8

    Default Re: Archiving large graphs (part II)

    In article
    <supernews.com 
    Doc O'Leary <example.com> wrote: 
    > If it didn't make a difference, you should have still went with the
    > right way instead of doing it manually. NSArchiver doesn't have a
    > (known) problem with recursive encoding (objects are uniqued in an
    > archive); any advice you got in that matter should be disregarded.[/ref]

    Well.. in the previous round I had with this thing, it turned out that
    the recursive archiving would not work with NSArchiver, but it did
    work with NSKeyedArchiver.
     
    > Trust me, there isn't. Having written custom NSCoder subclasses for
    > STEnterprise, I ran into a lot of issues and none of them had to do with
    > archive sizes. I'm talking about testing with hundreds of thousands of
    > objects and archives of over 100MB.[/ref]
     

    I won't argue with that.. ;)

    The only reason the thought of the problem being in NSKeyedArchiver or
    NSDoent was that the problem in the previous round was solved by
    replacing NSArchiver with NSKeyedArchiver. But yes, I agree the
    problem is most likely in my code. In fact, I hope so, because that
    means I can fix it.
     
    > When you fix the methods to call designated initializers as I noted,
    > sure. If you're still having problems, that is.[/ref]

    I'm not entirely sure what you mean. But I've changed the
    initWithCoder in RootClass.m to look like this (and made similar
    changes in the other classes):

    -(id)initWithCoder:(NSCoder *)coder
    {
    if (self =[super init])
    {
    [coder decodeValueOfObjCType:encode(int) at:&theExtent];

    aList = [[coder decodeObject] retain];
    bList = [[coder decodeObject] retain];
    }
    return self;
    }

    And at this point I have to ask: What is "if (self =[super init])"
    for? It seems it tells the superclass to initialise itself and test
    whether it succeeded or not?

    It still crashes, btw..

    --
    C Lund, www.notam02.no/~clund
    C Guest

  9. #9

    Default Re: Archiving large graphs (part II)

    In article <twistedsys.net>,
    Michael Ash <com> wrote:
     
    > >
    > > If it didn't make a difference, you should have still went with the
    > > right way instead of doing it manually. NSArchiver doesn't have a
    > > (known) problem with recursive encoding (objects are uniqued in an
    > > archive); any advice you got in that matter should be disregarded.[/ref]
    >
    > That is not strictly true. Both NSArchiver and NSKeyedArchiver encode
    > objects in a recursive fashion, so a large, complex object graph can cause
    > the program to run out of stack space and crash.[/ref]

    OK, I see what you're saying. Not having access to Apple's
    implementation, I can't say if they're following the object graph using
    stack space. If so, then there may indeed be an inherent limitation on
    the depth. However, I don't know if that's what the OP is running in to
    (it sounded more like they had thousands of objects, not thousands of
    levels deep), or if it's other problems in their code.
     

    I'm not sure that is necessarily true. I'll have to look over
    STEnterprise to see what limitations it has in that regard, but it seems
    like something that could be worked around within the API. That is, an
    archive is at it's heart a bunch of objects and relationships between
    those objects. The stack issue comes into play when you decode the
    relationships at the same time you decode the objects. It seems like an
    archiver would be free to decode starting at the deeper points in the
    graph.
     

    Which, seemingly, the NSCoder could take care of itself. If NSArchiver
    doesn't do it, I'm definitely going to try to make STEnterprise handle
    such persistence.
    Doc Guest

  10. #10

    Default Re: Archiving large graphs (part II)

    In article <chello.com>,
    C Lund <no> wrote:
     

    But with existing bugs in the code, it is still hard to point fingers.
    If there is an issue with Apple's code (and Mike made a good case for
    that being possible), you'd still have to report it with clean code so
    that they can more easily correct their code.
     

    It's for the same thing every object's -init method calls it: to
    properly initialize the object. Calling the proper super method is
    especially important for NSCoding because substitutions can be made for
    things like class clusters. That's all in the doentation.
     

    Well ship me off the project, then! :-) I'm really interested in
    seeing if this causes problems for my NSCoder subclass, too.
    Doc Guest

  11. #11

    Default Re: Archiving large graphs (part II)

    On Wed, 23 Jun 2004, Doc O'Leary wrote:
     
    >
    > OK, I see what you're saying. Not having access to Apple's
    > implementation, I can't say if they're following the object graph using
    > stack space. If so, then there may indeed be an inherent limitation on
    > the depth. However, I don't know if that's what the OP is running in to
    > (it sounded more like they had thousands of objects, not thousands of
    > levels deep), or if it's other problems in their code.[/ref]

    I have crashed NSArchiver and NSKeyedArchiver by encoding trees that were
    thousands or tens of thousands of objects deep, and I can confirm that
    they encode recursively. The OP had a complex relationship of objects, and
    depending on how his methods are written (using encodeObject: instead of
    encodeConditionalObject:, for example), his tree could end up causing deep
    recursion.
     
    >
    > I'm not sure that is necessarily true. I'll have to look over
    > STEnterprise to see what limitations it has in that regard, but it seems
    > like something that could be worked around within the API. That is, an
    > archive is at it's heart a bunch of objects and relationships between
    > those objects. The stack issue comes into play when you decode the
    > relationships at the same time you decode the objects. It seems like an
    > archiver would be free to decode starting at the deeper points in the
    > graph.[/ref]

    You're right on that point. However, it's possible to construct a graph
    that has no "deepest" part; consider a circular linked list with a hundred
    thousand objects in it. The problem is that the fact that -initWithCoder:
    could potentially return a different object than the one you sent the
    message to, and the existence of -awakeFromCoder: pretty much mandates
    recursive coding. When an object calls -decodeObject, you have to call
    -initWithCoder:, and if -initWithCoder: calls -decodeObject, you wander
    off into recursion. I have also written NSCoder subclasses and unless I
    missed a technique, there is no way to get around doing recursion in some
    cases.

    Interestingly, there's a general problem with NSCoder's API. If two
    objects refer to each other and they both return placeholder objects in
    -awakeFromCoder:, I don't think it's possible to correctly reconstruct the
    object graph in the unarchiver no matter what you do, unless you do
    something ugly like creating proxies for every decoded object.

    If you can guarantee that a given object will return self from
    -initWithCoder: (and since it's doented to do so, that could be taken
    as a requirement) and that it either doesn't implement -awakeFromCoder: or
    doesn't return a different object from it, then you could decode things in
    a nonrecursive manner.
     
    >
    > Which, seemingly, the NSCoder could take care of itself. If NSArchiver
    > doesn't do it, I'm definitely going to try to make STEnterprise handle
    > such persistence.[/ref]

    Making the encoder handle it is pretty easy, but making the decoder handle
    is, as I discussed above, difficult or impossible. That means that you
    need to write your code with those limitations in mind.

    The simple fact is that NSCoder is designed to deal with relatively small
    groups of objects; this is made obvious by the fact that NSKeyedArchiver
    is unbelievably slow encoding object graphs of any sort of complexity.
    They really exist to create and load nibs, and other small files, and the
    ability to use them for large, complex things is a kind of bonus that
    doesn't always work, depending on what you do.
    Michael Guest

  12. #12

    Default Re: Archiving large graphs (part II)

    In article
    <supernews.com 
    Doc O'Leary <example.com> wrote: 
    > Well ship me off the project, then! :-) I'm really interested in
    > seeing if this causes problems for my NSCoder subclass, too.[/ref]

    Will do. B)

    Do I remove the "nospam" to get a valid email address?

    --
    C Lund, www.notam02.no/~clund
    C Guest

  13. #13

    Default Re: Archiving large graphs (part II)

    In article <twistedsys.net>,
    Michael Ash <com> wrote:
     

    Sure, but there were more immediate errors that I saw which needed
    fixing before I wanted to get into the possibility of limitations in
    Apple's NSArchiver.
     

    You're right, of course. While recursion doesn't necessarily have to be
    done on the stack, the API makes it essentially impossible to handle
    that kind of structure. In general, Apple has too many different APIs
    for maintaining states/relationships in objects. Off the top of my head
    I can think of NSCoder (and related serialization code), NSUndoManager,
    and faulting in EOF (essentially dead for ObjC, though). It would be
    really nice if they got behind one common solution.
     

    Well, much of that problem lies not with NSCoder, but with NSArchiver.
    NSKeyedArchiver moves things in the right direction, but it does still
    leave developers wanting. Locking things up in a serialized
    representation isn't really all that useful. A database has a much
    greater value, and that is why I felt a need to at least write
    STEnterprise when Apple dropped the ball on EOF.
    Doc Guest

  14. #14

    Default Re: Archiving large graphs (part II)

    On Thu, 24 Jun 2004, Doc O'Leary wrote:
     
    >
    > Sure, but there were more immediate errors that I saw which needed
    > fixing before I wanted to get into the possibility of limitations in
    > Apple's NSArchiver.[/ref]

    Yes, I was ignoring them because I didn't have anything to add, not
    because I didn't think they were important.
     
    >
    > Well, much of that problem lies not with NSCoder, but with NSArchiver.
    > NSKeyedArchiver moves things in the right direction, but it does still
    > leave developers wanting. Locking things up in a serialized
    > representation isn't really all that useful. A database has a much
    > greater value, and that is why I felt a need to at least write
    > STEnterprise when Apple dropped the ball on EOF.[/ref]

    You're right that NSKeyedArchiver is at fault with the speed issues; it's
    obviously possible to make keyed archivers that are much faster. However,
    the API that NSCoder prevents does mandate recursive behavior, which
    brings limitations on what kinds of object graphs you can encode. I'm not
    sure how to improve the API,though, and it's pointless anyway, since we're
    stuck with what we have.
    Michael Guest

  15. #15

    Default Re: Archiving large graphs (part II)

    In article
    <supernews.com 
    Doc O'Leary <example.com> wrote:
     

    It should be in your mail now. B)

    --
    C Lund, www.notam02.no/~clund
    C Guest

  16. #16

    Default Re: Archiving large graphs (part II)

    In article <twistedsys.net>,
    Michael Ash <com> wrote:
     

    So, does this mean I'd be better off encoding, for instance, object
    indexes rather than pointers and then rebuilding the graph after all
    the objects have been loaded?

    Or perhaps I should forget about NSCoder and write my own archiving
    routines?

    --
    C Lund, www.notam02.no/~clund
    C Guest

  17. #17

    Default Re: Archiving large graphs (part II)

    On Fri, 25 Jun 2004, C Lund wrote:
     
    >
    > So, does this mean I'd be better off encoding, for instance, object
    > indexes rather than pointers and then rebuilding the graph after all
    > the objects have been loaded?[/ref]

    You don't really even need to go that far. NSCoder has two encoding
    methods, -encodeObject: and -encodeConditionalObject:. The latter only
    encodes the given object if somebody else also encodes it. It's normally
    used for things like "parent" relationships, where if the parent is in the
    archive, you want to keep the link, but if it's not, you don't want to
    force it to be included. Since -encodeConditionalObject: never directly
    encodes the object you give it, it will never trigger recursive behavior.

    You could write your objects' encoding methods to use
    -encodeConditionalObject: to encode your "peer" relationships between
    objects. Then when you archive the entire graph, you can archive them
    sequentially and never worry about overflow.

    You will still have to worry about speed and archive output size, but
    those are not as bad as crashes.

    This is where I toot my own horn. If you fix your crashes but find that
    speed and archive size are a problem, check out my own MAKeyedArchiver.
    It's about ten times faster than NSKeyedArchiver and produces files about
    half the size. It leaves off some error checking, but as long as your code
    is already correct it can work as a drop-in replacement to NSKeyedArchiver
    and NSKeyedUnarchiver. You can get it here:

    http://www.mikeash.com/software/MAKeyedArchiver/MAKeyedArchiver.tgz
     

    You might consider it. The "bonus" I describe above really is good, and
    it's nice not to have to write your own file format, but eventually you
    can end up spending more time wrestling with the limitations of the
    existing stuff than you'd spend making something new.

    In a similar situation, I stuck with NSCoder and worked around its
    limitations by avoiding recursive encoding as I detailed above, and
    eventually writing my own archiver to get around speed problems. There is
    something to be said for sticking with the standard approach.
    Michael Guest

  18. #18

    Default Re: Archiving large graphs (part II)

    In article <chello.com>,
    C Lund <no> wrote:
     
    > Doc O'Leary <example.com> wrote:

    >
    > It should be in your mail now. B)[/ref]

    Hmm.. I haven't heard from you since I mailed it to you.. Did you
    receive the project or are you still waiting for it?

    --
    C Lund, www.notam02.no/~clund
    C Guest

  19. #19

    Default Re: Archiving large graphs (part II)

    In article <twistedsys.net>,
    Michael Ash <com> wrote:
     
    > You don't really even need to go that far. NSCoder has two encoding
    > methods, -encodeObject: and -encodeConditionalObject:. The latter only
    > encodes the given object if somebody else also encodes it. It's normally
    > used for things like "parent" relationships, where if the parent is in the
    > archive, you want to keep the link, but if it's not, you don't want to
    > force it to be included. Since -encodeConditionalObject: never directly
    > encodes the object you give it, it will never trigger recursive behavior.[/ref]
     

    That's what I did the previous time we went through this problem. And
    it worked great once I had upgraded to 10.3 (so I could use
    NSKeyedArchiver - encodeConditionalObject doesn't seem to work
    properly under 10.1).

    However, now that I've moved my app to a doent format, the thing
    crashes when *decoding*. And I can't see any "decodeConditionalObject"
    in the doentation...
     
     
     

    I'll think about it. But somehow, using other people's code isn't
    quite as satisfying as using my own. I'm sure you understand. B)

    --
    C Lund, www.notam02.no/~clund
    C Guest

  20. #20

    Default Re: Archiving large graphs (part II)

    In article <chello.com>,
    C Lund <no> wrote:
     

    Oh, I got it, but I didn't really have time to look at it until the
    weekend and it's a bit . . . complex (but I'm sure you knew that :-). I
    don't know where to begin other than saying "you're stuffed". That is,
    everything looks massively interconnected such that, yes, it's a nasty
    stack/API issue. The reason it sometimes works and then doesn't with
    different OS version is probably that Apple changes how its objects
    archive internally from time to time; in particular I recall NSArray
    breaking my NSCoder subclass under Panther.

    But all hope is not lost! It's hard to tell when looking at an isolated
    example, but it seems to me your entire data structure could be redone
    to eliminate the problem. In addition to avoiding the archiver
    problems, it may be computationally less expensive to do the math in
    access methods rather than maintain a graph using arrays.

    That is, it seems to me that you're mainly defining a matrix of A
    objects with a related B object matrix (or two, depending on how you
    model the relationships), all of which have a easy-to-compute formula
    that relates them. You chose to encode that formula into web of
    attachment arrays at the time of creation, but I'm betting things would
    be better all around if you just had a lookup function or three to
    access related objects.
    Doc Guest

Page 1 of 2 12 LastLast

Similar Threads

  1. Creating PDFs, part colour, part B&W doent
    By Jacqui_Knight@adobeforums.com in forum Adobe Indesign Windows
    Replies: 5
    Last Post: May 15th, 07:46 PM
  2. Large scale website design - Part 2
    By JakeFlynn in forum Macromedia ColdFusion
    Replies: 8
    Last Post: March 10th, 06:32 PM
  3. Replies: 5
    Last Post: February 16th, 09:04 AM
  4. Replies: 1
    Last Post: February 11th, 12:08 PM
  5. Archiving large graphs
    By C Lund in forum Mac Programming
    Replies: 22
    Last Post: October 3rd, 02:32 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139