<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def calculate_positions(positions):
 """Calculates position information"""

    current_position = {'data-x': 0,
                        'data-y': 0,
                        'data-z': 0,
                        'data-rotate-x': 0,
                        'data-rotate-y': 0,
                        'data-rotate-z': 0,
                        'data-scale': 1,
                        }

    positer = iter(positions)
    position = next(positer)
    _update_position(current_position, position)

    while True:

        if 'path' in position:
            # Start of a new path!
            path = position['path']
            # Follow the path specification
            first_point = _pos_to_cord(current_position)

            # Paths that end in Z or z are closed.
            closed_path = path.strip()[-1].upper() == 'Z'
            path = parse_path(path)

            # Find out how many positions should be calculated:
            count = 1
            last = False
            deferred_positions = []
            while True:
                try:
                    position = next(positer)
                    deferred_positions.append(position)
                except StopIteration:
                    last = True  # This path goes to the end
                    break
                if not position.get('is_path') or 'path' in position:
                    # The end of the path, or the start of a new one
                    break
                count += 1

            if count < 2:
                raise AssertionError("The path specification is only used for "
                                     "one slide, which makes it pointless.")

            if closed_path:
                # This path closes in on itself. Skip the last part, so that
                # the first and last step doesn't overlap.
                endcount = count + 1
            else:
                endcount = count

            multiplier = (endcount * DEFAULT_MOVEMENT) / path.length()
            offset = path.point(0)

            path_iter = iter(deferred_positions)
            for x in range(count):

                point = path.point(x / (endcount - 1))
                point = ((point - offset) * multiplier) + first_point

                current_position.update(_coord_to_pos(point))

                rotation = _path_angle(path, x / (endcount - 1))
                current_position['data-rotate-z'] = rotation
                yield current_position.copy()
                try:
                    position = next(path_iter)
                except StopIteration:
                    last = True
                    break
                _update_position(current_position, position)

            if last:
                break

            continue

        yield current_position.copy()
        try:
            position = next(positer)
        except StopIteration:
            break
        _update_position(current_position, position)